]> andersk Git - gssapi-openssh.git/commitdiff
Initial revision
authorjbasney <jbasney>
Mon, 11 Mar 2002 15:10:35 +0000 (15:10 +0000)
committerjbasney <jbasney>
Mon, 11 Mar 2002 15:10:35 +0000 (15:10 +0000)
290 files changed:
openssh/.cvsignore [new file with mode: 0644]
openssh/CREDITS [new file with mode: 0644]
openssh/ChangeLog [new file with mode: 0644]
openssh/INSTALL [new file with mode: 0644]
openssh/LICENCE [new file with mode: 0644]
openssh/Makefile.in [new file with mode: 0644]
openssh/OVERVIEW [new file with mode: 0644]
openssh/README [new file with mode: 0644]
openssh/README.smartcard [new file with mode: 0644]
openssh/RFC.nroff [new file with mode: 0644]
openssh/TODO [new file with mode: 0644]
openssh/WARNING.RNG [new file with mode: 0644]
openssh/acconfig.h [new file with mode: 0644]
openssh/aclocal.m4 [new file with mode: 0644]
openssh/atomicio.c [new file with mode: 0644]
openssh/atomicio.h [new file with mode: 0644]
openssh/auth-bsdauth.c [new file with mode: 0644]
openssh/auth-chall.c [new file with mode: 0644]
openssh/auth-krb4.c [new file with mode: 0644]
openssh/auth-krb5.c [new file with mode: 0644]
openssh/auth-options.c [new file with mode: 0644]
openssh/auth-options.h [new file with mode: 0644]
openssh/auth-pam.c [new file with mode: 0644]
openssh/auth-pam.h [new file with mode: 0644]
openssh/auth-passwd.c [new file with mode: 0644]
openssh/auth-rh-rsa.c [new file with mode: 0644]
openssh/auth-rhosts.c [new file with mode: 0644]
openssh/auth-rsa.c [new file with mode: 0644]
openssh/auth-sia.c [new file with mode: 0644]
openssh/auth-sia.h [new file with mode: 0644]
openssh/auth-skey.c [new file with mode: 0644]
openssh/auth.c [new file with mode: 0644]
openssh/auth.h [new file with mode: 0644]
openssh/auth1.c [new file with mode: 0644]
openssh/auth2-chall.c [new file with mode: 0644]
openssh/auth2-pam.c [new file with mode: 0644]
openssh/auth2-pam.h [new file with mode: 0644]
openssh/auth2.c [new file with mode: 0644]
openssh/authfd.c [new file with mode: 0644]
openssh/authfd.h [new file with mode: 0644]
openssh/authfile.c [new file with mode: 0644]
openssh/authfile.h [new file with mode: 0644]
openssh/bufaux.c [new file with mode: 0644]
openssh/bufaux.h [new file with mode: 0644]
openssh/buffer.c [new file with mode: 0644]
openssh/buffer.h [new file with mode: 0644]
openssh/canohost.c [new file with mode: 0644]
openssh/canohost.h [new file with mode: 0644]
openssh/channels.c [new file with mode: 0644]
openssh/channels.h [new file with mode: 0644]
openssh/cipher.c [new file with mode: 0644]
openssh/cipher.h [new file with mode: 0644]
openssh/clientloop.c [new file with mode: 0644]
openssh/clientloop.h [new file with mode: 0644]
openssh/compat.c [new file with mode: 0644]
openssh/compat.h [new file with mode: 0644]
openssh/compress.c [new file with mode: 0644]
openssh/compress.h [new file with mode: 0644]
openssh/config.guess [new file with mode: 0755]
openssh/config.sub [new file with mode: 0755]
openssh/configure.ac [new file with mode: 0644]
openssh/contrib/README [new file with mode: 0644]
openssh/contrib/caldera/openssh.spec [new file with mode: 0644]
openssh/contrib/caldera/ssh-host-keygen [new file with mode: 0755]
openssh/contrib/caldera/sshd.init [new file with mode: 0755]
openssh/contrib/caldera/sshd.pam [new file with mode: 0644]
openssh/contrib/chroot.diff [new file with mode: 0644]
openssh/contrib/cygwin/README [new file with mode: 0644]
openssh/contrib/cygwin/ssh-host-config [new file with mode: 0644]
openssh/contrib/cygwin/ssh-user-config [new file with mode: 0644]
openssh/contrib/gnome-ssh-askpass.c [new file with mode: 0644]
openssh/contrib/hpux/README [new file with mode: 0644]
openssh/contrib/hpux/egd [new file with mode: 0644]
openssh/contrib/hpux/egd.rc [new file with mode: 0755]
openssh/contrib/hpux/sshd [new file with mode: 0644]
openssh/contrib/hpux/sshd.rc [new file with mode: 0755]
openssh/contrib/redhat/openssh.spec [new file with mode: 0644]
openssh/contrib/redhat/sshd.init [new file with mode: 0755]
openssh/contrib/redhat/sshd.pam [new file with mode: 0644]
openssh/contrib/redhat/sshd.pam-7.x [new file with mode: 0644]
openssh/contrib/solaris/README [new file with mode: 0644]
openssh/contrib/solaris/buildpkg.sh [new file with mode: 0755]
openssh/contrib/solaris/opensshd.in [new file with mode: 0755]
openssh/contrib/ssh-copy-id [new file with mode: 0644]
openssh/contrib/ssh-copy-id.1 [new file with mode: 0644]
openssh/contrib/sshd.pam.freebsd [new file with mode: 0644]
openssh/contrib/sshd.pam.generic [new file with mode: 0644]
openssh/contrib/suse/openssh.spec [new file with mode: 0644]
openssh/contrib/suse/rc.config.sshd [new file with mode: 0644]
openssh/contrib/suse/rc.sshd [new file with mode: 0644]
openssh/crc32.c [new file with mode: 0644]
openssh/crc32.h [new file with mode: 0644]
openssh/deattack.c [new file with mode: 0644]
openssh/deattack.h [new file with mode: 0644]
openssh/defines.h [new file with mode: 0644]
openssh/dh.c [new file with mode: 0644]
openssh/dh.h [new file with mode: 0644]
openssh/dispatch.c [new file with mode: 0644]
openssh/dispatch.h [new file with mode: 0644]
openssh/entropy.c [new file with mode: 0644]
openssh/entropy.h [new file with mode: 0644]
openssh/fixpaths [new file with mode: 0755]
openssh/fixprogs [new file with mode: 0755]
openssh/getput.h [new file with mode: 0644]
openssh/groupaccess.c [new file with mode: 0644]
openssh/groupaccess.h [new file with mode: 0644]
openssh/hostfile.c [new file with mode: 0644]
openssh/hostfile.h [new file with mode: 0644]
openssh/includes.h [new file with mode: 0644]
openssh/install-sh [new file with mode: 0755]
openssh/kex.c [new file with mode: 0644]
openssh/kex.h [new file with mode: 0644]
openssh/kexdh.c [new file with mode: 0644]
openssh/kexgex.c [new file with mode: 0644]
openssh/key.c [new file with mode: 0644]
openssh/key.h [new file with mode: 0644]
openssh/log.c [new file with mode: 0644]
openssh/log.h [new file with mode: 0644]
openssh/loginrec.c [new file with mode: 0644]
openssh/loginrec.h [new file with mode: 0644]
openssh/logintest.c [new file with mode: 0644]
openssh/mac.c [new file with mode: 0644]
openssh/mac.h [new file with mode: 0644]
openssh/match.c [new file with mode: 0644]
openssh/match.h [new file with mode: 0644]
openssh/md5crypt.c [new file with mode: 0644]
openssh/md5crypt.h [new file with mode: 0644]
openssh/mdoc2man.pl [new file with mode: 0644]
openssh/misc.c [new file with mode: 0644]
openssh/misc.h [new file with mode: 0644]
openssh/mkinstalldirs [new file with mode: 0755]
openssh/moduli [new file with mode: 0644]
openssh/mpaux.c [new file with mode: 0644]
openssh/mpaux.h [new file with mode: 0644]
openssh/myproposal.h [new file with mode: 0644]
openssh/nchan.c [new file with mode: 0644]
openssh/nchan.ms [new file with mode: 0644]
openssh/nchan2.ms [new file with mode: 0644]
openssh/openbsd-compat/.cvsignore [new file with mode: 0644]
openssh/openbsd-compat/Makefile.in [new file with mode: 0644]
openssh/openbsd-compat/base64.c [new file with mode: 0644]
openssh/openbsd-compat/base64.h [new file with mode: 0644]
openssh/openbsd-compat/bindresvport.c [new file with mode: 0644]
openssh/openbsd-compat/bindresvport.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-arc4random.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-arc4random.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-cray.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-cray.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-cygwin_util.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-cygwin_util.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-misc.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-misc.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-nextstep.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-nextstep.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-snprintf.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-snprintf.h [new file with mode: 0644]
openssh/openbsd-compat/bsd-waitpid.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-waitpid.h [new file with mode: 0644]
openssh/openbsd-compat/daemon.c [new file with mode: 0644]
openssh/openbsd-compat/daemon.h [new file with mode: 0644]
openssh/openbsd-compat/dirname.c [new file with mode: 0644]
openssh/openbsd-compat/dirname.h [new file with mode: 0644]
openssh/openbsd-compat/fake-gai-errnos.h [new file with mode: 0644]
openssh/openbsd-compat/fake-getaddrinfo.c [new file with mode: 0644]
openssh/openbsd-compat/fake-getaddrinfo.h [new file with mode: 0644]
openssh/openbsd-compat/fake-getnameinfo.c [new file with mode: 0644]
openssh/openbsd-compat/fake-getnameinfo.h [new file with mode: 0644]
openssh/openbsd-compat/fake-queue.h [new file with mode: 0644]
openssh/openbsd-compat/fake-regex.h [new file with mode: 0644]
openssh/openbsd-compat/fake-socket.h [new file with mode: 0644]
openssh/openbsd-compat/getcwd.c [new file with mode: 0644]
openssh/openbsd-compat/getcwd.h [new file with mode: 0644]
openssh/openbsd-compat/getgrouplist.c [new file with mode: 0644]
openssh/openbsd-compat/getgrouplist.h [new file with mode: 0644]
openssh/openbsd-compat/getopt.c [new file with mode: 0644]
openssh/openbsd-compat/getopt.h [new file with mode: 0644]
openssh/openbsd-compat/glob.c [new file with mode: 0644]
openssh/openbsd-compat/glob.h [new file with mode: 0644]
openssh/openbsd-compat/inet_aton.c [new file with mode: 0644]
openssh/openbsd-compat/inet_aton.h [new file with mode: 0644]
openssh/openbsd-compat/inet_ntoa.c [new file with mode: 0644]
openssh/openbsd-compat/inet_ntoa.h [new file with mode: 0644]
openssh/openbsd-compat/inet_ntop.c [new file with mode: 0644]
openssh/openbsd-compat/inet_ntop.h [new file with mode: 0644]
openssh/openbsd-compat/mktemp.c [new file with mode: 0644]
openssh/openbsd-compat/mktemp.h [new file with mode: 0644]
openssh/openbsd-compat/openbsd-compat.h [new file with mode: 0644]
openssh/openbsd-compat/readpassphrase.c [new file with mode: 0644]
openssh/openbsd-compat/readpassphrase.h [new file with mode: 0644]
openssh/openbsd-compat/realpath.c [new file with mode: 0644]
openssh/openbsd-compat/realpath.h [new file with mode: 0644]
openssh/openbsd-compat/rresvport.c [new file with mode: 0644]
openssh/openbsd-compat/rresvport.h [new file with mode: 0644]
openssh/openbsd-compat/setenv.c [new file with mode: 0644]
openssh/openbsd-compat/setenv.h [new file with mode: 0644]
openssh/openbsd-compat/setproctitle.c [new file with mode: 0644]
openssh/openbsd-compat/setproctitle.h [new file with mode: 0644]
openssh/openbsd-compat/sigact.c [new file with mode: 0644]
openssh/openbsd-compat/sigact.h [new file with mode: 0644]
openssh/openbsd-compat/strlcat.c [new file with mode: 0644]
openssh/openbsd-compat/strlcat.h [new file with mode: 0644]
openssh/openbsd-compat/strlcpy.c [new file with mode: 0644]
openssh/openbsd-compat/strlcpy.h [new file with mode: 0644]
openssh/openbsd-compat/strmode.c [new file with mode: 0644]
openssh/openbsd-compat/strmode.h [new file with mode: 0644]
openssh/openbsd-compat/strsep.c [new file with mode: 0644]
openssh/openbsd-compat/strsep.h [new file with mode: 0644]
openssh/packet.c [new file with mode: 0644]
openssh/packet.h [new file with mode: 0644]
openssh/pathnames.h [new file with mode: 0644]
openssh/radix.c [new file with mode: 0644]
openssh/radix.h [new file with mode: 0644]
openssh/readconf.c [new file with mode: 0644]
openssh/readconf.h [new file with mode: 0644]
openssh/readpass.c [new file with mode: 0644]
openssh/readpass.h [new file with mode: 0644]
openssh/rijndael.c [new file with mode: 0644]
openssh/rijndael.h [new file with mode: 0644]
openssh/rsa.c [new file with mode: 0644]
openssh/rsa.h [new file with mode: 0644]
openssh/scard.c [new file with mode: 0644]
openssh/scard.h [new file with mode: 0644]
openssh/scard/Makefile.in [new file with mode: 0644]
openssh/scard/Ssh.bin [new file with mode: 0644]
openssh/scard/Ssh.bin.uu [new file with mode: 0644]
openssh/scard/Ssh.java [new file with mode: 0644]
openssh/scp.1 [new file with mode: 0644]
openssh/scp.c [new file with mode: 0644]
openssh/servconf.c [new file with mode: 0644]
openssh/servconf.h [new file with mode: 0644]
openssh/serverloop.c [new file with mode: 0644]
openssh/serverloop.h [new file with mode: 0644]
openssh/session.c [new file with mode: 0644]
openssh/session.h [new file with mode: 0644]
openssh/sftp-client.c [new file with mode: 0644]
openssh/sftp-client.h [new file with mode: 0644]
openssh/sftp-common.c [new file with mode: 0644]
openssh/sftp-common.h [new file with mode: 0644]
openssh/sftp-glob.c [new file with mode: 0644]
openssh/sftp-glob.h [new file with mode: 0644]
openssh/sftp-int.c [new file with mode: 0644]
openssh/sftp-int.h [new file with mode: 0644]
openssh/sftp-server.8 [new file with mode: 0644]
openssh/sftp-server.c [new file with mode: 0644]
openssh/sftp.1 [new file with mode: 0644]
openssh/sftp.c [new file with mode: 0644]
openssh/sftp.h [new file with mode: 0644]
openssh/ssh-add.1 [new file with mode: 0644]
openssh/ssh-add.c [new file with mode: 0644]
openssh/ssh-agent.1 [new file with mode: 0644]
openssh/ssh-agent.c [new file with mode: 0644]
openssh/ssh-dss.c [new file with mode: 0644]
openssh/ssh-dss.h [new file with mode: 0644]
openssh/ssh-keygen.1 [new file with mode: 0644]
openssh/ssh-keygen.c [new file with mode: 0644]
openssh/ssh-keyscan.1 [new file with mode: 0644]
openssh/ssh-keyscan.c [new file with mode: 0644]
openssh/ssh-rsa.c [new file with mode: 0644]
openssh/ssh-rsa.h [new file with mode: 0644]
openssh/ssh.1 [new file with mode: 0644]
openssh/ssh.c [new file with mode: 0644]
openssh/ssh.h [new file with mode: 0644]
openssh/ssh1.h [new file with mode: 0644]
openssh/ssh2.h [new file with mode: 0644]
openssh/ssh_config [new file with mode: 0644]
openssh/ssh_prng_cmds.in [new file with mode: 0644]
openssh/sshconnect.c [new file with mode: 0644]
openssh/sshconnect.h [new file with mode: 0644]
openssh/sshconnect1.c [new file with mode: 0644]
openssh/sshconnect2.c [new file with mode: 0644]
openssh/sshd.8 [new file with mode: 0644]
openssh/sshd.c [new file with mode: 0644]
openssh/sshd_config [new file with mode: 0644]
openssh/sshlogin.c [new file with mode: 0644]
openssh/sshlogin.h [new file with mode: 0644]
openssh/sshpty.c [new file with mode: 0644]
openssh/sshpty.h [new file with mode: 0644]
openssh/sshtty.c [new file with mode: 0644]
openssh/sshtty.h [new file with mode: 0644]
openssh/tildexpand.c [new file with mode: 0644]
openssh/tildexpand.h [new file with mode: 0644]
openssh/ttymodes.c [new file with mode: 0644]
openssh/ttymodes.h [new file with mode: 0644]
openssh/uidswap.c [new file with mode: 0644]
openssh/uidswap.h [new file with mode: 0644]
openssh/uuencode.c [new file with mode: 0644]
openssh/uuencode.h [new file with mode: 0644]
openssh/version.h [new file with mode: 0644]
openssh/xmalloc.c [new file with mode: 0644]
openssh/xmalloc.h [new file with mode: 0644]

diff --git a/openssh/.cvsignore b/openssh/.cvsignore
new file mode 100644 (file)
index 0000000..a473d1f
--- /dev/null
@@ -0,0 +1,21 @@
+ssh
+scp
+sshd
+ssh-add
+ssh-keygen
+ssh-keyscan
+ssh-agent
+sftp-server
+sftp
+configure
+config.h.in
+config.h
+config.status
+config.cache
+config.log
+stamp-h.in
+Makefile
+ssh_prng_cmds
+*.out
+*.0
+buildit.sh
diff --git a/openssh/CREDITS b/openssh/CREDITS
new file mode 100644 (file)
index 0000000..c591e5c
--- /dev/null
@@ -0,0 +1,93 @@
+Tatu Ylonen <ylo@cs.hut.fi> - Creator of SSH
+
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, 
+Theo de Raadt, and Dug Song - Creators of OpenSSH
+
+Alain St-Denis <Alain.St-Denis@ec.gc.ca> - Irix fix
+Alexandre Oliva <oliva@lsd.ic.unicamp.br> - AIX fixes
+Andre Lucas <andre.lucas@dial.pipex.com> - new login code, many fixes
+Andreas Steinmetz <ast@domdv.de> - Shadow password expiry support
+Andrew McGill <andrewm@datrix.co.za> - SCO fixes
+Andrew Morgan <morgan@transmeta.com> - PAM bugfixes
+Andrew Stribblehill <a.d.stribblehill@durham.ac.uk> - Bugfixes
+Andy Sloane <andy@guildsoftware.com> - bugfixes
+Aran Cox <acox@cv.telegroup.com> - SCO bugfixes
+Arkadiusz Miskiewicz <misiek@pld.org.pl> - IPv6 compat fixes
+Ben Lindstrom <mouring@eviladmin.org> - NeXT support
+Ben Taylor <bent@clark.net> - Solaris debugging and fixes
+Bratislav ILICH <bilic@zepter.ru> - Configure fix
+Charles Levert <charles@comm.polymtl.ca> - SunOS 4 & bug fixes
+Chip Salzenberg <chip@valinux.com> - Assorted patches
+Chris Adams <cmadams@hiwaay.net> - OSF SIA support
+Chris Saia <csaia@wtower.com> - SuSE packaging
+Chris, the Young One <cky@pobox.com> - Password auth fixes
+Christos Zoulas <christos@zoulas.com> - Autoconf fixes
+Chun-Chung Chen <cjj@u.washington.edu> - RPM fixes
+Corinna Vinschen <vinschen@cygnus.com> - Cygwin support
+Dan Brosemer <odin@linuxfreak.com> - Autoconf support, build fixes
+Darren Hall <dhall@virage.org> - AIX patches
+David Agraz <dagraz@jahoopa.com> - Build fixes
+David Del Piero <David.DelPiero@qed.qld.gov.au> - bug fixes
+David Hesprich <darkgrue@gue-tech.org> - Configure fixes
+David Rankin <drankin@bohemians.lexington.ky.us> - libwrap, AIX, NetBSD fixes
+Ed Eden <ede370@stl.rural.usda.gov> - configure fixes
+Garrick James <garrick@james.net> - configure fixes
+Gary E. Miller <gem@rellim.com> - SCO support
+Ged Lodder <lodder@yacc.com.au> - HPUX fixes and enhancements
+Gert Doering <gd@hilb1.medat.de> - bug and portability fixes
+HARUYAMA Seigo <haruyama@klab.org> - Translations & doc fixes
+Hideaki YOSHIFUJI <yoshfuji@ecei.tohoku.ac.jp> - IPv6 and bug fixes
+Hiroshi Takekawa <takekawa@sr3.t.u-tokyo.ac.jp> - Configure fixes
+Holger Trapp <Holger.Trapp@Informatik.TU-Chemnitz.DE> - KRB4/AFS config patch
+IWAMURO Motonori <iwa@mmp.fujitsu.co.jp> - bugfixes
+Jani Hakala <jahakala@cc.jyu.fi> - Patches
+Jarno Huuskonen <jhuuskon@hytti.uku.fi> - Bugfixes
+Jim Knoble <jmknoble@jmknoble.cx> - Many patches
+Jonchen (email unknown) - the original author of PAM support of SSH
+Juergen Keil <jk@tools.de> - scp bugfixing
+KAMAHARA Junzo <kamahara@cc.kshosen.ac.jp> - Configure fixes
+Kees Cook <cook@cpoint.net> - scp fixes
+Kenji Miyake <kenji@miyake.org> - Configure fixes
+Kevin O'Connor <kevin_oconnor@standardandpoors.com> - RSAless operation
+Kevin Steves <stevesk@pobox.com> - HP support, bugfixes, improvements
+Kiyokazu SUTO <suto@ks-and-ks.ne.jp> - Bugfixes
+Larry Jones <larry.jones@sdrc.com> - Bugfixes
+Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE> - Bugfixes
+Marc G. Fournier <marc.fournier@acadiau.ca> - Solaris patches
+Mark D. Baushke <mdb@juniper.net> - bug fixes
+Martin Johansson <fatbob@acc.umu.se> - Linux fixes
+Mark D. Roth <roth+openssh@feep.net> - Features, bug fixes
+Mark Miller <markm@swoon.net> - Bugfixes
+Matt Richards <v2matt@btv.ibm.com> - AIX patches
+Michael Stone <mstone@cs.loyola.edu> - Irix enhancements
+Nakaji Hiroyuki <nakaji@tutrp.tut.ac.jp> - Sony News-OS patch
+Nalin Dahyabhai <nalin.dahyabhai@pobox.com> - PAM environment patch
+Nate Itkin <nitkin@europa.com> - SunOS 4.1.x fixes
+Niels Kristian Bech Jensen <nkbj@image.dk> - Assorted patches
+Pavel Kankovsky <peak@argo.troja.mff.cuni.cz> - Security fixes
+Pavel Troller <patrol@omni.sinus.cz> - Bugfixes
+Pekka Savola <pekkas@netcore.fi> - Bugfixes
+Peter Kocks <peter.kocks@baygate.com> - Makefile fixes
+Phil Hands <phil@hands.com> - Debian scripts, assorted patches
+Phil Karn <karn@ka9q.ampr.org> - Autoconf fixes
+Philippe WILLEM <Philippe.WILLEM@urssaf.fr> - Bugfixes
+Phill Camp <P.S.S.Camp@ukc.ac.uk> - login code fix
+Rip Loomis <loomisg@cist.saic.com> - Solaris package support, fixes
+SAKAI Kiyotaka <ksakai@kso.netwk.ntt-at.co.jp> - Multiple bugfixes
+Simon Wilkinson <sxw@dcs.ed.ac.uk> - PAM fixes
+Svante Signell <svante.signell@telia.com> - Bugfixes
+Thomas Neumann <tom@smart.ruhr.de> - Shadow passwords
+Tim Rice <tim@multitalents.net> - Portability & SCO fixes
+Tobias Oetiker <oetiker@ee.ethz.ch> - Bugfixes
+Tom Bertelson's <tbert@abac.com> - AIX auth fixes
+Tor-Ake Fransson <torake@hotmail.com> - AIX support
+Tudor Bosman <tudorb@jm.nu> - MD5 password support
+Udo Schweigert <ust@cert.siemens.de> - ReliantUNIX support
+Zack Weinberg <zack@wolery.cumb.org> - GNOME askpass enhancement
+
+Apologies to anyone I have missed.
+
+Damien Miller <djm@mindrot.org>
+
+$Id$
+
diff --git a/openssh/ChangeLog b/openssh/ChangeLog
new file mode 100644 (file)
index 0000000..d79e7fb
--- /dev/null
@@ -0,0 +1,6922 @@
+20011202
+ - (djm) Syn with OpenBSD OpenSSH-3.0.2
+   - markus@cvs.openbsd.org
+     [session.c sshd.8 version.h]
+     Don't allow authorized_keys specified environment variables when 
+     UseLogin in active
+
+20011115
+ - (djm) Fix IPv4 default in ssh-keyscan. Spotted by Dan Astoorian 
+   <djast@cs.toronto.edu> Fix from markus@
+ - (djm) Release 3.0.1p1
+
+20011113
+ - (djm) Fix early (and double) free of remote user when using Kerberos. 
+   Patch from Simon Wilkinson <simon@sxw.org.uk>
+ - (djm) AIX login{success,failed} changes. Move loginsuccess call to 
+   do_authenticated. Call loginfailed for protocol 2 failures > MAX like 
+   we do for protocol 1. Reports from Ralf Wenk <wera0003@fh-karlsruhe.de>,
+   K.Wolkersdorfer@fz-juelich.de and others
+ - (djm) OpenBSD CVS Sync
+   - dugsong@cvs.openbsd.org 2001/11/11 18:47:10
+     [auth-krb5.c]
+     fix krb5 authorization check. found by <jhawk@MIT.EDU>. from 
+     art@, deraadt@ ok
+   - markus@cvs.openbsd.org  2001/11/12 11:17:07
+     [servconf.c]
+     enable authorized_keys2 again. tested by fries@
+   - markus@cvs.openbsd.org  2001/11/13 02:03:57
+     [version.h]
+     enter 3.0.1
+ - (djm) Bump RPM package versions
+
+20011112
+ - (djm) Makefile correctness fix from Mark D. Baushke <mdb@juniper.net>
+ - (djm) Cygwin config patch from Corinna Vinschen <vinschen@redhat.com>
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/10/24 08:41:41
+     [sshd.c]
+     mention remote port in debug message
+   - markus@cvs.openbsd.org 2001/10/24 08:41:20
+     [ssh.c]
+     remove unused
+   - markus@cvs.openbsd.org 2001/10/24 08:51:35
+     [clientloop.c ssh.c]
+     ignore SIGPIPE early, makes ssh work if agent dies, netbsd-pr via itojun@
+   - markus@cvs.openbsd.org 2001/10/24 19:57:40
+     [clientloop.c]
+     make ~& (backgrounding) work again for proto v1; add support ~& for v2, too
+   - markus@cvs.openbsd.org 2001/10/25 21:14:32
+     [ssh-keygen.1 ssh-keygen.c]
+     better docu for fingerprinting, ok deraadt@
+   - markus@cvs.openbsd.org 2001/10/29 19:27:15
+     [sshconnect2.c]
+     hostbased: check for client hostkey before building chost
+   - markus@cvs.openbsd.org 2001/10/30 20:29:09
+     [ssh.1]
+     ssh.1
+   - markus@cvs.openbsd.org 2001/11/07 16:03:17
+     [packet.c packet.h sshconnect2.c]
+     pad using the padding field from the ssh2 packet instead of sending
+     extra ignore messages. tested against several other ssh servers.
+   - markus@cvs.openbsd.org 2001/11/07 21:40:21
+     [ssh-rsa.c]
+     ssh_rsa_sign/verify: SSH_BUG_SIGBLOB not supported
+   - markus@cvs.openbsd.org 2001/11/07 22:10:28
+     [ssh-dss.c ssh-rsa.c]
+     missing free and sync dss/rsa code.
+   - markus@cvs.openbsd.org 2001/11/07 22:12:01
+     [sshd.8]
+     s/Keepalive/KeepAlive/; from openbsd@davidkrause.com
+   - markus@cvs.openbsd.org 2001/11/07 22:41:51
+     [auth2.c auth-rh-rsa.c]
+     unused includes
+   - markus@cvs.openbsd.org 2001/11/07 22:53:21
+     [channels.h]
+     crank c->path to 256 so they can hold a full hostname; dwd@bell-labs.com
+   - markus@cvs.openbsd.org 2001/11/08 10:51:08
+     [readpass.c]
+     don't strdup too much data; from gotoh@taiyo.co.jp; ok millert.
+   - markus@cvs.openbsd.org 2001/11/08 17:49:53
+     [ssh.1]
+     mention setuid root requirements; noted by cnorris@csc.UVic.ca; ok stevesk@
+   - markus@cvs.openbsd.org 2001/11/08 20:02:24
+     [auth.c]
+     don't print ROOT in CAPS for the authentication messages, i.e.
+       Accepted publickey for ROOT from 127.0.0.1 port 42734 ssh2
+     becomes
+       Accepted publickey for root from 127.0.0.1 port 42734 ssh2
+   - markus@cvs.openbsd.org 2001/11/09 18:59:23
+     [clientloop.c serverloop.c]
+     don't memset too much memory, ok millert@
+     original patch from jlk@kamens.brookline.ma.us via nalin@redhat.com
+   - markus@cvs.openbsd.org 2001/11/10 13:19:45
+     [sshd.c]
+     cleanup libwrap support (remove bogus comment, bogus close(), add 
+     debug, etc).
+   - markus@cvs.openbsd.org 2001/11/10 13:22:42
+     [ssh-rsa.c]
+     KNF (unexpand)
+   - markus@cvs.openbsd.org 2001/11/10 13:37:20
+     [packet.c]
+     remove extra debug()
+   - markus@cvs.openbsd.org 2001/11/11 13:02:31
+     [servconf.c]
+     make AuthorizedKeysFile2 fallback to AuthorizedKeysFile if 
+     AuthorizedKeysFile is specified.
+ - (djm) Reorder portable-specific server options so that they come first. 
+   This should help reduce diff collisions for new server options (as they
+   will appear at the end)
+
+20011109
+ - (stevesk) auth-pam.c: use do_pam_authenticate(PAM_DISALLOW_NULL_AUTHTOK)
+   if permit_empty_passwd == 0 so null password check cannot be bypassed.
+   jayaraj@amritapuri.com OpenBSD bug 2168
+   - markus@cvs.openbsd.org 2001/11/09 19:08:35
+     [sshd.c]
+     remove extra trailing dot from log message; pilot@naughty.monkey.org
+
+20011103
+ - (tim) [ contrib/caldera/openssh.spec contrib/caldera/sshd.init] Updates 
+   from Raymund Will <ray@caldera.de>
+   [acconfig.h configure.in] Clean up login checks.
+   Problem reported by Jim Knoble <jmknoble@pobox.com>
+
+20011101
+ - (djm) Compat define for OpenSSL < 0.9.6 (No OPENSSL_free)
+
+20011031
+ - (djm) Unsmoke drugs: config files should be noreplace.
+
+20011030
+ - (djm) Redhat RPM spec: remove noreplace from config files, allow IPv6 
+   by default (can force IPv4 using --define "noipv6 1")
+
+20011029
+ - (tim) [TODO defines.h loginrec.c] Change the references to configure.in
+   to configure.ac
+
+20011028
+ - (djm) Avoid bug in Solaris PAM libs
+ - (djm) Disconnect if no tty and PAM reports password expired
+ - (djm) Fix for PAM password changes being echoed (from stevesk)
+ - (stevesk) Fix compile problem with PAM password change fix
+ - (stevesk) README: zlib location is http://www.gzip.org/zlib/
+
+20011027
+ - (tim) [configure.ac] Fixes for ReliantUNIX (don't use libucb)
+   Patch by Robert Dahlem <Robert.Dahlem@siemens.com>
+
+20011026
+ - (bal) Set the correct current time in login_utmp_only().  Patch by
+   Wayne Davison <wayned@users.sourceforge.net>
+ - (tim) [scard/Makefile.in] Fix install: when building outside of source
+        tree and using --src=/full_path/to/openssh
+        Patch by Mark D. Baushke <mdb@juniper.net>
+
+20011025
+ - (bal) Use VDISABLE if _POSIX_VDISABLE is set in readpassphrase.c.  Patch
+   by todd@
+ - (tim) [configure.ac] Give path given in --with-xxx= for pcre,zlib, and
+        tcp-wrappers precedence over system libraries and includes.
+        Report from Dave Dykstra <dwd@bell-labs.com>
+
+20011024
+ - (bal) Should be 3.0p1 not 3.0p2.  Corrected version.h already.
+ - (tim) configure.in -> configure.ac
+
+20011023
+ - (bal) Updated version to 3.0p1 in preparing for release.
+ - (bal) Added 'PAM_TTY_KLUDGE' to Solaris platform.
+ - (tim) [configure.in] Fix test for broken dirname. Based on patch from
+        Dave Dykstra <dwd@bell-labs.com>. Remove un-needed test for zlib.h.
+        [contrib/caldera/openssh.spec, contrib/redhat/openssh.spec,
+        contrib/suse/openssh.spec] Update version to match version.h
+
+20011022
+ - (djm) Fix fd leak in loginrec.c (ro fd to lastlog was left open).
+   Report from Michal Zalewski <lcamtuf@coredump.cx>
+
+20011021
+ - (tim) [configure.in] Clean up library testing. Add optional PATH to
+        --with-pcre, --with-zlib, and --with-tcp-wrappers. Based on
+        patch by albert chin (china@thewrittenword.com)
+        Re-arange AC_CHECK_HEADERS and AC_CHECK_FUNCS for eaiser reading
+        of patches to configure.in. Replace obsolete AC_STRUCT_ST_BLKSIZE
+        with AC_CHECK_MEMBERS. Add test for broken dirname() on
+        Solaris 2.5.1 by Dan Astoorian <djast@cs.toronto.edu>
+        [acconfig.h aclocal.m4 defines.h configure.in] Better socklen_t test.
+        patch by albert chin (china@thewrittenword.com)
+        [scp.c] Replace obsolete HAVE_ST_BLKSIZE with
+        HAVE_STRUCT_STAT_ST_BLKSIZE.
+        [Makefile.in] When running make in top level, always do make
+        in openbsd-compat. patch by Dave Dykstra <dwd@bell-labs.com>
+
+20011019
+ - (bal) Fixed up init.d symlink issue and piddir stuff.  Patches by
+   Zoran Milojevic <Zoran.Milojevic@SS8.com> and j.petersen@msh.de 
+
+20011012
+ - (djm) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/10/10 22:18:47
+     [channels.c channels.h clientloop.c nchan.c serverloop.c]
+     [session.c session.h]
+     try to keep channels open until an exit-status message is sent.
+     don't kill the login shells if the shells stdin/out/err is closed.
+     this should now work:
+     ssh -2n localhost 'exec > /dev/null 2>&1; sleep 10; exit 5'; echo ?
+   - markus@cvs.openbsd.org 2001/10/11 13:45:21
+     [session.c]
+     delay detach of session if a channel gets closed but the child is 
+     still alive.  however, release pty, since the fd's to the child are 
+     already closed.
+   - markus@cvs.openbsd.org 2001/10/11 15:24:00
+     [clientloop.c]
+     clear select masks if we return before calling select().
+ - (djm) "make veryclean" fix from Tom Holroyd <tomh@po.crl.go.jp>
+ - (djm) Clean some autoconf-2.52 junk when doing "make distclean"
+ - (djm) Cleanup sshpty.c a little
+ - (bal) First wave of contrib/solaris/ package upgrades.  Still more
+   work needs to be done, but it is a 190% better then the stuff we
+   had before!
+ - (bal) Minor bug fix in contrib/solaris/opensshd.in .. $etcdir was not
+   set right.
+
+20011010
+ - (djm) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/10/04 14:34:16
+     [key.c]
+     call OPENSSL_free() for memory allocated by openssl; from chombier@mac.com
+   - markus@cvs.openbsd.org 2001/10/04 15:05:40
+     [channels.c serverloop.c]
+     comment out bogus conditions for selecting on connection_in
+   - markus@cvs.openbsd.org 2001/10/04 15:12:37
+     [serverloop.c]
+     client_alive_check cleanup
+   - markus@cvs.openbsd.org 2001/10/06 00:14:50
+     [sshconnect.c]
+     remove unused argument
+   - markus@cvs.openbsd.org 2001/10/06 00:36:42
+     [session.c]
+     fix typo in error message, sync with do_exec_nopty
+   - markus@cvs.openbsd.org 2001/10/06 11:18:19
+     [sshconnect1.c sshconnect2.c sshconnect.c]
+     unify hostkey check error messages, simplify prompt.
+   - markus@cvs.openbsd.org 2001/10/07 10:29:52
+     [authfile.c]
+     grammer; Matthew_Clarke@mindlink.bc.ca
+   - markus@cvs.openbsd.org 2001/10/07 17:49:40
+     [channels.c channels.h]
+     avoid possible FD_ISSET overflow for channels established
+     during channnel_after_select() (used for dynamic channels).
+   - markus@cvs.openbsd.org 2001/10/08 11:48:57
+     [channels.c]
+     better debug
+   - markus@cvs.openbsd.org 2001/10/08 16:15:47
+     [sshconnect.c]
+     use correct family for -b option
+   - markus@cvs.openbsd.org 2001/10/08 19:05:05
+     [ssh.c sshconnect.c sshconnect.h ssh-keyscan.c]
+     some more IPv4or6 cleanup
+   - markus@cvs.openbsd.org 2001/10/09 10:12:08
+     [session.c]
+     chdir $HOME after krb_afslog(); from bbense@networking.stanford.edu
+   - markus@cvs.openbsd.org 2001/10/09 19:32:49
+     [session.c]
+     stat subsystem command before calling do_exec, and return error to client.
+   - markus@cvs.openbsd.org 2001/10/09 19:51:18
+     [serverloop.c]
+     close all channels if the connection to the remote host has been closed,
+     should fix sshd's hanging with WCHAN==wait
+   - markus@cvs.openbsd.org 2001/10/09 21:59:41
+     [channels.c channels.h serverloop.c session.c session.h]
+     simplify session close: no more delayed session_close, no more 
+     blocking wait() calls.
+ - (bal) removed two unsed headers in openbsd-compat/bsd-misc.c 
+ - (bal) seed_init() and seed_rng() required in ssh-keyscan.c
+
+20011007
+ - (bal) ssh-copy-id corrected permissions for .ssh/ and authorized_keys.
+   Prompted by Matthew Vernon <matthew@sel.cam.ac.uk> 
+
+20011005
+ - (bal) AES works under Cray, no more hack. 
+
+20011004
+ - (bal) nchan2.ms resync.  BSD License applied.
+
+20011003
+ - (bal) CVS ID fix up in version.h
+ - (bal) OpenBSD CVS Sync:
+   - markus@cvs.openbsd.org 2001/09/27 11:58:16
+     [compress.c]
+     mem leak; chombier@mac.com
+   - markus@cvs.openbsd.org 2001/09/27 11:59:37
+     [packet.c]
+     missing called=1; chombier@mac.com
+   - markus@cvs.openbsd.org 2001/09/27 15:31:17
+     [auth2.c auth2-chall.c sshconnect1.c]
+     typos; from solar
+   - camield@cvs.openbsd.org 2001/09/27 17:53:24
+     [sshd.8]
+     don't talk about compile-time options
+     ok markus@
+   - djm@cvs.openbsd.org 2001/09/28 12:07:09
+     [ssh-keygen.c]
+     bzero private key after loading to smartcard; ok markus@
+   - markus@cvs.openbsd.org 2001/09/28 15:46:29
+     [ssh.c]
+     bug: read user config first; report kaukasoi@elektroni.ee.tut.fi
+   - markus@cvs.openbsd.org 2001/10/01 08:06:28
+     [scp.c]
+     skip filenames containing \n; report jdamery@chiark.greenend.org.uk
+     and matthew@debian.org
+   - markus@cvs.openbsd.org 2001/10/01 21:38:53
+     [channels.c channels.h ssh.c sshd.c]
+     remove ugliness; vp@drexel.edu via angelos
+   - markus@cvs.openbsd.org 2001/10/01 21:51:16
+     [readconf.c readconf.h ssh.1 sshconnect.c]
+     add NoHostAuthenticationForLocalhost; note that the hostkey is
+     now check for localhost, too.
+   - djm@cvs.openbsd.org 2001/10/02 08:38:50
+     [ssh-add.c]
+     return non-zero exit code on error; ok markus@
+   - stevesk@cvs.openbsd.org 2001/10/02 22:56:09
+     [sshd.c]
+     #include "channels.h" for channel_set_af()
+   - markus@cvs.openbsd.org 2001/10/03 10:01:20
+     [auth.c]
+     use realpath() for homedir, too. from jinmei@isl.rdc.toshiba.co.jp
+
+20011001
+ - (stevesk) loginrec.c: fix type conversion problems exposed when using
+   64-bit off_t.
+       
+20010929
+ - (bal) move reading 'config.h' up higher.  Patch by albert chin
+   <china@thewrittenword.com)
+
+20010928
+ - (djm) OpenBSD CVS sync:
+   - djm@cvs.openbsd.org 2001/09/28 09:49:31
+     [scard.c]
+     Fix segv when smartcard communication error occurs during key load. 
+     ok markus@
+ - (djm) Update spec files for new x11-askpass
+
+20010927
+ - (stevesk) session.c: declare do_pre_login() before use
+   wayned@users.sourceforge.net
+
+20010925
+ - (djm) Pull in auth-krb5.c from OpenBSD CVS. NB. it is not currently used.
+ - (djm) Sync $sysconfdir/moduli
+ - (djm) Add AC_SYS_LARGEFILE configure test
+ - (djm) Avoid bad and unportable sprintf usage in compat code
+
+20010923
+ - (bal) updated ssh.c to mirror minor getopts 'extern int' formating done
+   by stevesk@
+ - (bal) Removed 'extern int optopt;' since it is dead wood.
+ - (bal) Updated all *.specs for 2.9.9p1 and updated version.h
+
+20010923
+ - (bal) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/09/23 11:09:13
+     [authfile.c]
+     relax permission check for private key files.
+   - markus@cvs.openbsd.org 2001/09/23 09:58:13
+     [LICENCE]
+     new rijndael implementation
+
+20010920
+ - (tim) [scard/Makefile.in] Don't strip the Java binary
+ - (stevesk) sun_len, SUN_LEN() configure stuff no longer required
+ - (bal) OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/09/20 00:15:54
+     [sshd.8]
+     fix ClientAliveCountMax
+   - markus@cvs.openbsd.org 2001/09/20 13:46:48
+     [auth2.c]
+     key_read returns now -1 or 1
+   - markus@cvs.openbsd.org 2001/09/20 13:50:40
+     [compat.c compat.h ssh.c]
+     bug compat: request a dummy channel for -N (no shell) sessions + 
+     cleanup; vinschen@redhat.com
+   - mouring@cvs.openbsd.org 2001/09/20 20:57:51
+     [sshd_config]
+     CheckMail removed.  OKed stevesk@
+
+20010919
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/09/19 10:08:51
+     [sshd.8]
+     command=xxx applies to subsystem now, too
+   - markus@cvs.openbsd.org 2001/09/19 13:23:29
+     [key.c]
+     key_read() now returns -1 on type mismatch, too
+   - stevesk@cvs.openbsd.org 2001/09/19 19:24:19
+     [readconf.c readconf.h scp.c sftp.c ssh.1]
+     add ClearAllForwardings ssh option and set it in scp and sftp; ok 
+     markus@
+   - stevesk@cvs.openbsd.org 2001/09/19 19:35:30
+     [authfd.c]
+     use sizeof addr vs. SUN_LEN(addr) for sockaddr_un.  Stevens 
+     blesses this and we do it this way elsewhere.  this helps in 
+     portable because not all systems have SUN_LEN() and 
+     sockaddr_un.sun_len.  ok markus@
+   - stevesk@cvs.openbsd.org 2001/09/19 21:04:53
+     [sshd.8]
+     missing -t in usage
+   - stevesk@cvs.openbsd.org 2001/09/19 21:41:57
+     [sshd.8]
+     don't advertise -V in usage; ok markus@
+ - (bal) openbsd-compat/vis.[ch] is dead wood.  Removed.
+
+20010918
+ - (djm) Configure support for smartcards. Based on Ben's work.
+ - (djm) Revert setgroups call, it causes problems on OS-X
+ - (djm) Avoid warning on BSDgetopt
+ - (djm) More makefile infrastructre for smartcard support, also based
+   on Ben's work
+ - (djm) Specify --datadir in RPM spec files so smartcard applet gets
+    put somewhere sane. Add Ssh.bin to manifest.
+ - (djm) Make smartcard support conditional in Redhat RPM spec
+ - (bal) LICENCE update.  Has not been done in a while.
+ - (stevesk) nchan.c: we use X/Open Sockets on HP-UX now so shutdown(2)
+   returns ENOTCONN vs. EINVAL for socket not connected; remove EINVAL
+   check. ok Lutz Jaenicke
+ - (bal) OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/09/17 17:57:57
+     [scp.1 scp.c sftp.1 sftp.c]
+     add -Fssh_config option; ok markus@
+   - stevesk@cvs.openbsd.org 2001/09/17 19:27:15
+     [kexdh.c kexgex.c key.c key.h ssh-dss.c ssh-keygen.c ssh-rsa.c]
+     u_char*/char* cleanup; ok markus
+   - markus@cvs.openbsd.org 2001/09/17 20:22:14
+     [scard.c]
+     never keep a connection to the smartcard open.
+     allows ssh-keygen -D U while the agent is running; report from 
+     jakob@
+   - stevesk@cvs.openbsd.org 2001/09/17 20:38:09
+     [sftp.1 sftp.c]
+     cleanup and document -1, -s and -S; ok markus@
+   - markus@cvs.openbsd.org 2001/09/17 20:50:22
+     [key.c ssh-keygen.c]
+     better error handling if you try to export a bad key to ssh.com
+   - markus@cvs.openbsd.org 2001/09/17 20:52:47
+     [channels.c channels.h clientloop.c]
+     try to fix agent-forwarding-backconnection-bug, as seen on HPUX, 
+     for example; with Lutz.Jaenicke@aet.TU-Cottbus.DE,
+   - markus@cvs.openbsd.org 2001/09/17 21:04:02
+     [channels.c serverloop.c]
+     don't send fake dummy packets on CR (\r)
+     bugreport from yyua@cs.sfu.ca via solar@@openwall.com
+   - markus@cvs.openbsd.org 2001/09/17 21:09:47
+     [compat.c]
+     more versions suffering the SSH_BUG_DEBUG bug;
+     3.0.x reported by dbutts@maddog.storability.com
+   - stevesk@cvs.openbsd.org 2001/09/17 23:56:07
+     [scp.1]
+     missing -B in usage string
+
+20010917
+ - (djm) x11-ssh-askpass-1.2.4 in RPM spec, revert workarounds
+ - (tim) [includes.h openbsd-compat/getopt.c openbsd-compat/getopt.h]
+        rename getopt() to BSDgetopt() to keep form conflicting with
+        system getopt().
+        [Makefile.in configure.in] disable filepriv until I can add
+        missing procpriv calls.
+
+20010916
+ - (djm) Workaround XFree breakage in RPM spec file
+ - (bal) OpenBSD CVS Sync
+    - markus@cvs.openbsd.org 2001/09/16 14:46:54
+      [session.c]
+      calls krb_afslog() after setting $HOME; mattiasa@e.kth.se; fixes
+      pr 1943b
+
+20010915
+ - (djm) Make do_pre_login static to avoid prototype #ifdef hell
+ - (djm) Sync scard/ stuff
+ - (djm) Redhat spec file cleanups from Pekka Savola <pekkas@netcore.fi> and
+   Redhat
+ - (djm) Redhat initscript config sanity checking from Pekka Savola 
+   <pekkas@netcore.fi>
+ - (djm) Clear supplemental groups at sshd start to prevent them from 
+   being propogated to random PAM modules. Based on patch from Redhat via
+   Pekka Savola <pekkas@netcore.fi>
+ - (djm) Make sure rijndael.c picks config.h
+ - (djm) Ensure that u_char gets defined
+
+20010914
+ - (bal) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/09/13
+     [rijndael.c rijndael.h]
+     missing $OpenBSD
+   - markus@cvs.openbsd.org 2001/09/14
+     [session.c]
+     command=xxx overwrites subsystems, too
+   - markus@cvs.openbsd.org 2001/09/14
+     [sshd.c]
+     typo
+
+20010913
+ - (bal) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/08/23 11:31:59
+     [cipher.c cipher.h]
+     switch to the optimised AES reference code from
+     http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-fst-3.0.zip
+
+20010912
+ - (bal) OpenBSD CVS Sync
+   - jakob@cvs.openbsd.org 2001/08/16 19:18:34
+     [servconf.c servconf.h session.c sshd.8]
+     deprecate CheckMail. ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/16 20:14:57
+     [ssh.1 sshd.8]
+     document case sensitivity for ssh, sshd and key file
+     options and arguments; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/17 18:59:47
+     [servconf.h]
+     typo in comment
+   - stevesk@cvs.openbsd.org 2001/08/21 21:47:42
+     [ssh.1 sshd.8]
+     minor typos and cleanup
+   - stevesk@cvs.openbsd.org 2001/08/22 16:21:21
+     [ssh.1]
+     hostname not optional; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/22 16:30:02
+     [sshd.8]
+     no rexd; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/22 17:45:16
+     [ssh.1]
+     document cipher des for protocol 1; ok deraadt@
+   - camield@cvs.openbsd.org 2001/08/23 17:59:31
+     [sshd.c]
+     end request with 0, not NULL
+     ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/23 18:02:48
+     [ssh-agent.1]
+     fix usage; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/23 18:08:59
+     [ssh-add.1 ssh-keyscan.1]
+     minor cleanup
+   - danh@cvs.openbsd.org 2001/08/27 22:02:13
+     [ssh-keyscan.c]
+     fix memory fault if non-existent filename is given to the -f option
+     ok markus@
+   - markus@cvs.openbsd.org 2001/08/28 09:51:26
+     [readconf.c]
+     don't set DynamicForward unless Host matches
+   - markus@cvs.openbsd.org 2001/08/28 15:39:48
+     [ssh.1 ssh.c]
+     allow: ssh -F configfile host
+   - markus@cvs.openbsd.org 2001/08/29 20:44:03
+     [scp.c]
+     clear the malloc'd buffer, otherwise source() will leak malloc'd 
+     memory; ok theo@
+   - stevesk@cvs.openbsd.org 2001/08/29 23:02:21
+     [sshd.8]
+     add text about -u0 preventing DNS requests; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/29 23:13:10
+     [ssh.1 ssh.c]
+     document -D and DynamicForward; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/29 23:27:23
+     [ssh.c]
+     validate ports for -L/-R; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/29 23:39:40
+     [ssh.1 sshd.8]
+     additional documentation for GatewayPorts; ok markus@
+   - naddy@cvs.openbsd.org 2001/08/30 15:42:36
+     [ssh.1]
+     add -D to synopsis line; ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/30 16:04:35
+     [readconf.c ssh.1]
+     validate ports for LocalForward/RemoteForward.
+     add host/port alternative syntax for IPv6 (like -L/-R).
+     ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/30 20:36:34
+     [auth-options.c sshd.8]
+     validate ports for permitopen key file option. add host/port
+     alternative syntax for IPv6. ok markus@
+   - markus@cvs.openbsd.org 2001/08/30 22:22:32
+     [ssh-keyscan.c]
+     do not pass pointers to longjmp; fix from wayne@blorf.net
+   - markus@cvs.openbsd.org 2001/08/31 11:46:39
+     [sshconnect2.c]
+     disable kbd-interactive if we don't get SSH2_MSG_USERAUTH_INFO_REQUEST
+     messages
+   - stevesk@cvs.openbsd.org 2001/09/03 20:58:33
+     [readconf.c readconf.h ssh.c]
+     fatal() for nonexistent -Fssh_config. ok markus@
+   - deraadt@cvs.openbsd.org 2001/09/05 06:23:07
+     [scp.1 sftp.1 ssh.1 ssh-agent.1 sshd.8 ssh-keygen.1 ssh-keyscan.1]
+     avoid first person in manual pages
+   - stevesk@cvs.openbsd.org 2001/09/12 18:18:25
+     [scp.c]
+     don't forward agent for non third-party copies; ok markus@
+
+20010815
+ - (bal) Fixed stray code in readconf.c that went in by mistake.
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/08/07 10:37:46
+     [authfd.c authfd.h]
+     extended failure messages from galb@vandyke.com
+   - deraadt@cvs.openbsd.org 2001/08/08 07:16:58
+     [scp.1]
+     when describing the -o option, give -o Protocol=1 as the specific example
+     since we are SICK AND TIRED of clueless people who cannot have difficulty
+     thinking on their own.
+   - markus@cvs.openbsd.org 2001/08/08 18:20:15
+     [uidswap.c]
+     permanently_set_uid is a noop if user is not privilegued;
+     fixes bug on solaris; from sbi@uchicago.edu
+   - markus@cvs.openbsd.org 2001/08/08 21:34:19
+     [uidswap.c]
+     undo last change; does not work for sshd
+   - jakob@cvs.openbsd.org 2001/08/11 22:51:27
+     [ssh.c tildexpand.c]
+     fix more paths beginning with "//"; <bradshaw@staff.crosswalk.com>. 
+     ok markus@
+   - stevesk@cvs.openbsd.org 2001/08/13 23:38:54
+     [scp.c]
+     don't need main prototype (also sync with rcp); ok markus@
+   - markus@cvs.openbsd.org 2001/08/14 09:23:02
+     [sftp.1 sftp-int.c]
+     "bye"; hk63a@netscape.net
+   - stevesk@cvs.openbsd.org 2001/08/14 17:54:29
+     [scp.1 sftp.1 ssh.1]
+     consistent documentation and example of ``-o ssh_option'' for sftp and
+     scp; document keyword=argument for ssh.
+ - (bal) QNX resync.   OK tim@
+
+20010814
+ - (stevesk) sshpty.c, cray.[ch]: whitespace, formatting and cleanup
+   for some #ifdef _CRAY code; ok wendyp@cray.com
+ - (stevesk) sshpty.c: return 0 on error in cray pty code;
+   ok wendyp@cray.com
+ - (stevesk) bsd-cray.c: utmp strings are not C strings
+ - (stevesk) bsd-cray.c: more cleanup; ok wendyp@cray.com
+
+20010812
+ - (djm) Fix detection of long long int support. Based on patch from 
+   Michael Stone <mstone@cs.loyola.edu>. ok stevesk, tim
+
+20010808
+ - (bal) Minor correction to inet_ntop.h.  _BSD_RRESVPORT_H should be
+   _BSD_INET_NTOP_H.  Pointed out by Mark Miller <markm@swoon.net> 
+
+20010807
+ - (tim) [configure.in sshconnect.c openbsd-compat/Makefile.in
+        openbsd-compat/openbsd-compat.h ] Add inet_ntop.c inet_ntop.h back
+        in. Needed for sshconnect.c
+        [sshconnect.c] fix INET6_ADDRSTRLEN for non IPv6 machines
+        [configure.in] make tests with missing libraries fail
+        patch by Wendy Palm <wendyp@cray.com>
+        Added openbsd-compat/bsd-cray.h. Selective patches from
+        William L. Jones <jones@mail.utexas.edu> 
+
+20010806
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/07/22 21:32:27
+     [sshpty.c]
+     update comment
+   - pvalchev@cvs.openbsd.org 2001/07/22 21:32:42
+     [ssh.1]
+     There is no option "Compress", point to "Compression" instead; ok 
+     markus
+   - markus@cvs.openbsd.org 2001/07/22 22:04:19
+     [readconf.c ssh.1]
+     enable challenge-response auth by default; ok millert@
+   - markus@cvs.openbsd.org 2001/07/22 22:24:16
+     [sshd.8]
+     Xr login.conf
+   - markus@cvs.openbsd.org 2001/07/23 09:06:28
+     [sshconnect2.c]
+     reorder default sequence of userauth methods to match ssh behaviour:
+     hostbased,publickey,keyboard-interactive,password
+   - markus@cvs.openbsd.org 2001/07/23 12:47:05
+     [ssh.1]
+     sync PreferredAuthentications
+   - aaron@cvs.openbsd.org 2001/07/23 14:14:18
+     [ssh-keygen.1]
+     Fix typo.
+   - stevesk@cvs.openbsd.org 2001/07/23 18:14:58
+     [auth2.c auth-rsa.c]
+     use %lu; ok markus@
+   - stevesk@cvs.openbsd.org 2001/07/23 18:21:46
+     [xmalloc.c]
+     no zero size xstrdup() error; ok markus@
+   - markus@cvs.openbsd.org 2001/07/25 11:59:35
+     [scard.c]
+     typo in comment
+   - markus@cvs.openbsd.org 2001/07/25 14:35:18
+     [readconf.c ssh.1 ssh.c sshconnect.c]
+     cleanup connect(); connection_attempts 4 -> 1; from 
+     eivind@freebsd.org
+   - stevesk@cvs.openbsd.org 2001/07/26 17:18:22
+     [sshd.8 sshd.c]
+     add -t option to test configuration file and keys; pekkas@netcore.fi
+     ok markus@
+   - rees@cvs.openbsd.org 2001/07/26 20:04:27
+     [scard.c ssh-keygen.c]
+     Inquire Cyberflex class for 0xf0 cards
+     change aid to conform to 7816-5
+     remove gratuitous fid selects
+   - millert@cvs.openbsd.org 2001/07/27 14:50:45
+     [ssh.c]
+     If smart card support is compiled in and a smart card is being used
+     for authentication, make it the first method used.  markus@ OK
+   - deraadt@cvs.openbsd.org 2001/07/27 17:26:16
+     [scp.c]
+     shorten lines
+   - markus@cvs.openbsd.org 2001/07/28 09:21:15
+     [sshd.8]
+     cleanup some RSA vs DSA vs SSH1 vs SSH2 notes
+   - mouring@cvs.openbsd.org 2001/07/29 17:02:46
+     [scp.1]
+     Clarified -o option in scp.1  OKed by Markus@
+   - jakob@cvs.openbsd.org 2001/07/30 16:06:07
+     [scard.c scard.h]
+     better errorcodes from sc_*; ok markus@
+   - stevesk@cvs.openbsd.org 2001/07/30 16:23:30
+     [rijndael.c rijndael.h]
+     new BSD-style license:
+     Brian Gladman <brg@gladman.plus.com>:
+     >I have updated my code at:
+     >http://fp.gladman.plus.com/cryptography_technology/rijndael/index.htm
+     >with a copyright notice as follows:
+     >[...]
+     >I am not sure which version of my old code you are using but I am
+     >happy for the notice above to be substituted for my existing copyright
+     >intent if this meets your purpose.
+   - jakob@cvs.openbsd.org 2001/07/31 08:41:10
+     [scard.c]
+     do not complain about missing smartcards. ok markus@
+   - jakob@cvs.openbsd.org 2001/07/31 09:28:44
+     [readconf.c readconf.h ssh.1 ssh.c]
+     add 'SmartcardDevice' client option to specify which smartcard device 
+     is used to access a smartcard used for storing the user's private RSA 
+     key. ok markus@.
+   - jakob@cvs.openbsd.org 2001/07/31 12:42:50
+     [sftp-int.c sftp-server.c]
+     avoid paths beginning with "//"; <vinschen@redhat.com>
+     ok markus@
+   - jakob@cvs.openbsd.org 2001/07/31 12:53:34
+     [scard.c]
+     close smartcard connection if card is missing
+   - markus@cvs.openbsd.org 2001/08/01 22:03:33
+     [authfd.c authfd.h readconf.c readconf.h scard.c scard.h ssh-add.c 
+      ssh-agent.c ssh.c]
+     use strings instead of ints for smartcard reader ids
+   - markus@cvs.openbsd.org 2001/08/01 22:16:45
+     [ssh.1 sshd.8]
+     refer to current ietf drafts for protocol v2
+   - markus@cvs.openbsd.org 2001/08/01 23:33:09
+     [ssh-keygen.c]
+     allow uploading RSA keys for non-default AUT0 (sha1 over passphrase 
+     like sectok).
+  - markus@cvs.openbsd.org 2001/08/01 23:38:45
+     [scard.c ssh.c]
+     support finish rsa keys.
+     free public keys after login -> call finish -> close smartcard.
+   - markus@cvs.openbsd.org 2001/08/02 00:10:17
+     [ssh-keygen.c]
+     add -D readerid option (download, i.e. print public RSA key to stdout).
+     check for card present when uploading keys.
+     use strings instead of ints for smartcard reader ids, too.
+   - jakob@cvs.openbsd.org 2001/08/02 08:58:35
+     [ssh-keygen.c]
+     change -u (upload smartcard key) to -U. ok markus@
+   - jakob@cvs.openbsd.org 2001/08/02 15:06:52
+     [ssh-keygen.c]
+     more verbose usage(). ok markus@
+   - jakob@cvs.openbsd.org 2001/08/02 15:07:23
+     [ssh-keygen.1]
+     document smartcard upload/download. ok markus@
+   - jakob@cvs.openbsd.org 2001/08/02 15:32:10
+     [ssh.c]
+     add smartcard to usage(). ok markus@
+   - jakob@cvs.openbsd.org 2001/08/02 15:43:57
+     [ssh-agent.c ssh.c ssh-keygen.c]
+     add /* SMARTCARD */ to #else/#endif. ok markus@
+  - jakob@cvs.openbsd.org 2001/08/02 16:14:05
+     [scard.c ssh-agent.c ssh.c ssh-keygen.c]
+     clean up some /* SMARTCARD */. ok markus@
+   - mpech@cvs.openbsd.org 2001/08/02 18:37:35
+     [ssh-keyscan.1]
+     o) .Sh AUTHOR -> .Sh AUTHORS;
+     o) .Sh EXAMPLE -> .Sh EXAMPLES;
+     o) Delete .Sh OPTIONS. Text moved to .Sh DESCRIPTION;
+     millert@ ok
+   - jakob@cvs.openbsd.org 2001/08/03 10:31:19
+     [ssh-add.1]
+     document smartcard options. ok markus@
+   - jakob@cvs.openbsd.org 2001/08/03 10:31:30
+     [ssh-add.c ssh-agent.c ssh-keyscan.c]
+     improve usage(). ok markus@
+   - markus@cvs.openbsd.org 2001/08/05 23:18:20
+     [ssh-keyscan.1 ssh-keyscan.c]
+     ssh 2 support; from wayned@users.sourceforge.net
+   - markus@cvs.openbsd.org 2001/08/05 23:29:58
+     [ssh-keyscan.c]
+     make -t dsa work with commercial servers, too
+   - stevesk@cvs.openbsd.org 2001/08/06 19:47:05
+     [scp.c]
+     use alarm vs. setitimer for portable; ok markus@
+ - (bal) ssh-keyscan double -lssh hack due to seed_rng().
+ - (bal) Second around of UNICOS patches.  A few other things left. 
+   Patches by William L. Jones <jones@mail.utexas.edu> 
+
+20010803
+ - (djm) Fix interrupted read in entropy gatherer. Spotted by markus@ on
+   a fast UltraSPARC.
+
+20010726
+ - (stevesk) use mysignal() in protocol 1 loop now that the SIGCHLD
+   handler has converged.
+
+20010725
+ - (bal) Added 'install-nokeys' to Makefile to assist package builders.
+
+20010724
+ - (bal) 4711 not 04711 for ssh binary.
+
+20010722
+ - (bal) Starting the Unicossmk merger.  File merged TODO, configure.in,
+        myproposal.h, ssh_prng_cmds.in, and openbsd-compat/Makefile.in.
+        Added openbsd-compat/bsd-cray.c.  Rest will be merged after
+        approval.  Selective patches from William L. Jones 
+        <jones@mail.utexas.edu> 
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/07/18 21:10:43
+     [sshpty.c]
+     pr #1946, allow sshd if /dev is readonly
+   - stevesk@cvs.openbsd.org 2001/07/18 21:40:40
+     [ssh-agent.c]
+     chdir("/") from bbraun@synack.net; ok markus@
+   - stevesk@cvs.openbsd.org 2001/07/19 00:41:44
+     [ssh.1]
+     escape chars are below now
+   - markus@cvs.openbsd.org 2001/07/20 14:46:11
+     [ssh-agent.c]
+     do not exit() from signal handlers; ok deraadt@
+   - stevesk@cvs.openbsd.org 2001/07/20 18:41:51
+     [ssh.1]
+     "the" command line
+
+20010719
+ - (tim) [configure.in] put inet_aton back in AC_CHECK_FUNCS.
+        report from Mark Miller <markm@swoon.net>
+
+20010718
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/07/14 15:10:17
+     [readpass.c sftp-client.c sftp-common.c sftp-glob.c]
+     delete spurious #includes; ok deraadt@ markus@
+   - markus@cvs.openbsd.org 2001/07/15 16:17:08
+     [serverloop.c]
+     schedule client alive for ssh2 only, greg@cheers.bungi.com
+   - stevesk@cvs.openbsd.org 2001/07/15 16:57:21
+     [ssh-agent.1]
+     -d will not fork; ok markus@
+   - stevesk@cvs.openbsd.org 2001/07/15 16:58:29
+     [ssh-agent.c]
+     typo in usage; ok markus@
+   - markus@cvs.openbsd.org 2001/07/17 20:48:42
+     [ssh-agent.c]
+     update maxfd if maxfd is closed; report from jmcelroy@dtgnet.com
+   - markus@cvs.openbsd.org 2001/07/17 21:04:58
+     [channels.c channels.h clientloop.c nchan.c serverloop.c]
+     keep track of both maxfd and the size of the malloc'ed fdsets.
+     update maxfd if maxfd gets closed.
+   - mouring@cvs.openbsd.org 2001/07/18 16:45:52
+     [scp.c]
+     Missing -o in scp usage()
+ - (bal) Cleaned up trailing spaces in ChangeLog.
+ - (bal) Allow sshd to switch user context without password for Cygwin.
+         Patch by Corinna Vinschen <vinschen@redhat.com>
+ - (bal) Updated cygwin README and ssh-host-config.  Patch by
+        Corinna Vinschen <vinschen@redhat.com>
+
+20010715
+ - (bal) Set "BROKEN_GETADDRINFO" for darwin platform.  Reported by
+   Josh Larios <jdlarios@cac.washington.edu>
+ - (tim) put openssh/openbsd-compat/inet_aton.[ch] back in.
+        needed by openbsd-compat/fake-getaddrinfo.c
+
+20010714
+ - (stevesk) change getopt() declaration
+ - (stevesk) configure.in: use ll suffix for long long constant
+   in snprintf() test
+
+20010713
+ - (djm) Enable /etc/nologin check on PAM systems, as some lack the
+   pam_nologin module. Report from William Yodlowsky
+   <bsd@openbsd.rutgers.edu>
+ - (djm) Revert dirname fix, a better one is on its way.
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/07/04 22:47:19
+     [ssh-agent.c]
+     ignore SIGPIPE when debugging, too
+   - markus@cvs.openbsd.org 2001/07/04 23:13:10
+     [scard.c scard.h ssh-agent.c]
+     handle card removal more gracefully, add sc_close() to scard.h
+   - markus@cvs.openbsd.org 2001/07/04 23:39:07
+     [ssh-agent.c]
+     for smartcards remove both RSA1/2 keys
+   - markus@cvs.openbsd.org 2001/07/04 23:49:27
+     [ssh-agent.c]
+     handle mutiple adds of the same smartcard key
+   - espie@cvs.openbsd.org 2001/07/05 11:43:33
+     [sftp-glob.c]
+     Directly cast to the right type. Ok markus@
+   - stevesk@cvs.openbsd.org 2001/07/05 20:32:47
+     [sshconnect1.c]
+     statement after label; ok dugsong@
+   - stevesk@cvs.openbsd.org 2001/07/08 15:23:38
+     [servconf.c]
+     fix ``MaxStartups max''; ok markus@
+   - fgsch@cvs.openbsd.org 2001/07/09 05:58:47
+     [ssh.c]
+     Use getopt(3); markus@ ok.
+   - deraadt@cvs.openbsd.org 2001/07/09 07:04:53
+     [session.c sftp-int.c]
+     correct type on last arg to execl(); nordin@cse.ogi.edu
+   - markus@cvs.openbsd.org 2001/07/10 21:49:12
+     [readpass.c]
+     don't panic if fork or pipe fail (just return an empty passwd).
+   - itojun@cvs.openbsd.org 2001/07/11 00:24:53
+     [servconf.c]
+     make it compilable in all 4 combination of KRB4/KRB5 settings.
+     dugsong ok
+     XXX isn't it sensitive to the order of -I/usr/include/kerberosIV and
+     -I/usr/include/kerberosV?
+   - markus@cvs.openbsd.org 2001/07/11 16:29:59
+     [ssh.c]
+     sort options string, fix -p, add -k
+   - markus@cvs.openbsd.org 2001/07/11 18:26:15
+     [auth.c]
+     no need to call dirname(pw->pw_dir).
+     note that dirname(3) modifies its argument on some systems.
+ - (djm) Reorder Makefile.in so clean targets work a little better when
+   run directly from Makefile.in
+ - (djm) Pull in getopt(3) from OpenBSD libc for the optreset extension.
+
+20010711
+ - (djm) dirname(3) may modify its argument on glibc and other systems.
+   Patch from markus@, spotted by Tom Holroyd <tomh@po.crl.go.jp>
+
+20010704
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/06/25 08:25:41
+     [channels.c channels.h cipher.c clientloop.c compat.c compat.h
+      hostfile.c kex.c kex.h key.c key.h nchan.c packet.c serverloop.c
+      session.c session.h sftp-server.c ssh-add.c ssh-agent.c uuencode.h]
+     update copyright for 2001
+   - markus@cvs.openbsd.org 2001/06/25 17:18:27
+     [ssh-keygen.1]
+     sshd(8) will never read the private keys, but ssh(1) does;
+     hugh@mimosa.com
+   - provos@cvs.openbsd.org 2001/06/25 17:54:47
+     [auth.c auth.h auth-rsa.c]
+     terminate secure_filename checking after checking homedir.  that way
+     it works on AFS.  okay markus@
+   - stevesk@cvs.openbsd.org 2001/06/25 20:26:37
+     [auth2.c sshconnect2.c]
+     prototype cleanup; ok markus@
+   - markus@cvs.openbsd.org 2001/06/26 02:47:07
+     [ssh-keygen.c]
+     allow loading a private RSA key to a cyberflex card.
+   - markus@cvs.openbsd.org 2001/06/26 04:07:06
+     [ssh-agent.1 ssh-agent.c]
+     add debug flag
+   - markus@cvs.openbsd.org 2001/06/26 04:59:59
+     [authfd.c authfd.h ssh-add.c]
+     initial support for smartcards in the agent
+   - markus@cvs.openbsd.org 2001/06/26 05:07:43
+     [ssh-agent.c]
+     update usage
+   - markus@cvs.openbsd.org 2001/06/26 05:33:34
+     [ssh-agent.c]
+     more smartcard support.
+   - mpech@cvs.openbsd.org 2001/06/26 05:48:07
+     [sshd.8]
+     remove unnecessary .Pp between .It;
+     millert@ ok
+   - markus@cvs.openbsd.org 2001/06/26 05:50:11
+     [auth2.c]
+     new interface for secure_filename()
+   - itojun@cvs.openbsd.org 2001/06/26 06:32:58
+     [atomicio.h authfd.h authfile.h auth.h auth-options.h bufaux.h
+      buffer.h canohost.h channels.h cipher.h clientloop.h compat.h
+      compress.h crc32.h deattack.h dh.h dispatch.h groupaccess.h
+      hostfile.h kex.h key.h log.h mac.h match.h misc.h mpaux.h packet.h
+      radix.h readconf.h readpass.h rsa.h]
+     prototype pedant.  not very creative...
+     - () -> (void)
+     - no variable names
+   - itojun@cvs.openbsd.org 2001/06/26 06:33:07
+     [servconf.h serverloop.h session.h sftp-client.h sftp-common.h
+      sftp-glob.h sftp-int.h sshconnect.h ssh-dss.h sshlogin.h sshpty.h
+      ssh-rsa.h tildexpand.h uidswap.h uuencode.h xmalloc.h]
+     prototype pedant.  not very creative...
+     - () -> (void)
+     - no variable names
+   - dugsong@cvs.openbsd.org 2001/06/26 16:15:25
+     [auth1.c auth.h auth-krb4.c auth-passwd.c readconf.c readconf.h
+      servconf.c servconf.h session.c sshconnect1.c sshd.c]
+     Kerberos v5 support for SSH1, mostly from Assar Westerlund
+     <assar@freebsd.org> and Bjorn Gronvall <bg@sics.se>. markus@ ok
+   - markus@cvs.openbsd.org 2001/06/26 17:25:34
+     [ssh.1]
+     document SSH_ASKPASS; fubob@MIT.EDU
+   - markus@cvs.openbsd.org 2001/06/26 17:27:25
+     [authfd.h authfile.h auth.h auth-options.h bufaux.h buffer.h
+      canohost.h channels.h cipher.h clientloop.h compat.h compress.h
+      crc32.h deattack.h dh.h dispatch.h groupaccess.c groupaccess.h
+      hostfile.h kex.h key.h log.c log.h mac.h misc.c misc.h mpaux.h
+      packet.h radix.h readconf.h readpass.h rsa.h servconf.h serverloop.h
+      session.h sftp-common.c sftp-common.h sftp-glob.h sftp-int.h
+      sshconnect.h ssh-dss.h sshlogin.h sshpty.h ssh-rsa.h sshtty.h
+      tildexpand.h uidswap.h uuencode.h xmalloc.h]
+     remove comments from .h, since they are cut&paste from the .c files
+     and out of sync
+   - dugsong@cvs.openbsd.org 2001/06/26 17:41:49
+     [servconf.c]
+     #include <kafs.h>
+   - markus@cvs.openbsd.org 2001/06/26 20:14:11
+     [key.c key.h ssh.c sshconnect1.c sshconnect2.c]
+     add smartcard support to the client, too (now you can use both
+     the agent and the client).
+   - markus@cvs.openbsd.org 2001/06/27 02:12:54
+     [serverloop.c serverloop.h session.c session.h]
+     quick hack to make ssh2 work again.
+   - markus@cvs.openbsd.org 2001/06/27 04:48:53
+     [auth.c match.c sshd.8]
+     tridge@samba.org
+   - markus@cvs.openbsd.org 2001/06/27 05:35:42
+     [ssh-keygen.c]
+     use cyberflex_inq_class to inquire class.
+   - markus@cvs.openbsd.org 2001/06/27 05:42:25
+     [rsa.c rsa.h ssh-agent.c ssh-keygen.c]
+     s/generate_additional_parameters/rsa_generate_additional_parameters/
+     http://www.humppa.com/
+   - markus@cvs.openbsd.org 2001/06/27 06:26:36
+     [ssh-add.c]
+     convert to getopt(3)
+   - stevesk@cvs.openbsd.org 2001/06/28 19:57:35
+     [ssh-keygen.c]
+     '\0' terminated data[] is ok; ok markus@
+   - markus@cvs.openbsd.org 2001/06/29 07:06:34
+     [ssh-keygen.c]
+     new error handling for cyberflex_*
+   - markus@cvs.openbsd.org 2001/06/29 07:11:01
+     [ssh-keygen.c]
+     initialize early
+   - stevesk@cvs.openbsd.org 2001/06/29 18:38:44
+     [clientloop.c]
+     sync function definition with declaration; ok markus@
+   - stevesk@cvs.openbsd.org 2001/06/29 18:40:28
+     [channels.c]
+     use socklen_t for getsockopt arg #5; ok markus@
+   - stevesk@cvs.openbsd.org 2001/06/30 18:08:40
+     [channels.c channels.h clientloop.c]
+     adress -> address; ok markus@
+   - markus@cvs.openbsd.org 2001/07/02 13:59:15
+     [serverloop.c session.c session.h]
+     wait until !session_have_children(); bugreport from
+     Lutz.Jaenicke@aet.TU-Cottbus.DE
+   - markus@cvs.openbsd.org 2001/07/02 22:29:20
+     [readpass.c]
+     do not return NULL, use "" instead.
+   - markus@cvs.openbsd.org 2001/07/02 22:40:18
+     [ssh-keygen.c]
+     update for sectok.h interface changes.
+   - markus@cvs.openbsd.org 2001/07/02 22:52:57
+     [channels.c channels.h serverloop.c]
+     improve cleanup/exit logic in ssh2:
+     stop listening to channels, detach channel users (e.g. sessions).
+     wait for children (i.e. dying sessions), send exit messages,
+     cleanup all channels.
+ - (bal) forget a few new files in sync up.
+ - (bal) Makefile fix up requires scard.c
+ - (stevesk) sync misc.h
+ - (stevesk) more sync for session.c
+ - (stevesk) sync servconf.h (comments)
+ - (tim) [contrib/caldera/openssh.spec] sync with Caldera
+ - (tim) [openbsd-compat/dirname.h] Remove ^M causing some compilers to
+        issue warning (line 1: tokens ignored at end of directive line)
+ - (tim) [sshconnect1.c] give the compiler something to do for success:
+        if KRB5 and AFS are not defined
+        (ERROR: "sshconnect1.c", line 1274: Syntax error before or at: })
+
+20010629
+ - (bal) Removed net_aton() since we don't use it any more
+ - (bal) Fixed _DISABLE_VPOSIX in readpassphrase.c.
+ - (bal) Updated zlib's home.  Thanks to David Howe <DaveHowe@gmx.co.uk>.
+ - (stevesk) remove _REENTRANT #define
+ - (stevesk) session.c: use u_int for envsize
+ - (stevesk) remove cli.[ch]
+
+20010628
+ - (djm) Sync openbsd-compat with -current libc
+ - (djm) Fix from Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE> for my
+   broken makefile
+ - (bal) Removed strtok_r() and inet_ntop() since they are no longer used.
+ - (bal) Remove getusershell() since it's no longer used.
+
+20010627
+ - (djm) Reintroduce pam_session call for non-pty sessions.
+ - (djm) Remove redundant and incorrect test for max auth attempts in
+   PAM kbdint code. Based on fix from Matthew Melvin
+  <matthewm@webcentral.com.au>
+ - (djm) Rename sysconfdir/primes => sysconfdir/moduli
+ - (djm) Oops, forgot make logic for primes=>moduli. Also try to rename
+   existing primes->moduli if it exists.
+ - (djm) Sync with -current openbsd-compat/readpassphrase.c:
+   - djm@cvs.openbsd.org 2001/06/27 13:23:30
+     typo, spotted by Tom Holroyd <tomh@po.crl.go.jp>; ok deraadt@
+ - (djm) Turn up warnings if gcc or egcs detected
+ - (stevesk) for HP-UX 11.X use X/Open socket interface;
+    pulls in modern socket prototypes and eliminates a number of compiler
+    warnings.  see xopen_networking(7).
+ - (stevesk) fix x11 forwarding from _PATH_XAUTH change
+ - (stevesk) use X/Open socket interface for HP-UX 10.X also
+
+20010625
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/06/21 21:08:25
+     [session.c]
+     don't reset forced_command (we allow multiple login shells in
+     ssh2); dwd@bell-labs.com
+   - mpech@cvs.openbsd.org 2001/06/22 10:17:51
+     [ssh.1 sshd.8 ssh-keyscan.1]
+     o) .Sh AUTHOR -> .Sh AUTHORS;
+     o) remove unnecessary .Pp;
+     o) better -mdoc style;
+     o) typo;
+     o) sort SEE ALSO;
+     aaron@ ok
+   - provos@cvs.openbsd.org 2001/06/22 21:27:08
+     [dh.c pathnames.h]
+     use /etc/moduli instead of /etc/primes, okay markus@
+   - provos@cvs.openbsd.org 2001/06/22 21:28:53
+     [sshd.8]
+     document /etc/moduli
+   - markus@cvs.openbsd.org 2001/06/22 21:55:49
+     [auth2.c auth-rsa.c pathnames.h ssh.1 sshd.8 sshd_config
+      ssh-keygen.1]
+     merge authorized_keys2 into authorized_keys.
+     authorized_keys2 is used for backward compat.
+     (just append authorized_keys2 to authorized_keys).
+   - provos@cvs.openbsd.org 2001/06/22 21:57:59
+     [dh.c]
+     increase linebuffer to deal with larger moduli; use rewind instead of
+     close/open
+   - markus@cvs.openbsd.org 2001/06/22 22:21:20
+     [sftp-server.c]
+     allow long usernames/groups in readdir
+   - markus@cvs.openbsd.org 2001/06/22 23:35:21
+     [ssh.c]
+     don't overwrite argv (fixes ssh user@host in 'ps'), report by ericj@
+   - deraadt@cvs.openbsd.org 2001/06/23 00:16:16
+     [scp.c]
+     slightly better care
+   - markus@cvs.openbsd.org 2001/06/23 00:20:57
+     [auth2.c auth.c auth.h auth-rh-rsa.c]
+     *known_hosts2 is obsolete for hostbased authentication and
+     only used for backward compat. merge ssh1/2 hostkey check
+     and move it to auth.c
+   - deraadt@cvs.openbsd.org 2001/06/23 02:33:05
+     [sftp.1 sftp-server.8 ssh-keygen.1]
+     join .%A entries; most by bk@rt.fm
+   - markus@cvs.openbsd.org 2001/06/23 02:34:33
+     [kexdh.c kexgex.c kex.h pathnames.h readconf.c servconf.h ssh.1
+      sshconnect1.c sshconnect2.c sshconnect.c sshconnect.h sshd.8]
+     get rid of known_hosts2, use it for hostkey lookup, but do not
+     modify.
+   - markus@cvs.openbsd.org 2001/06/23 03:03:59
+     [sshd.8]
+     draft-ietf-secsh-dh-group-exchange-01.txt
+   - markus@cvs.openbsd.org 2001/06/23 03:04:42
+     [auth2.c auth-rh-rsa.c]
+     restore correct ignore_user_known_hosts logic.
+   - markus@cvs.openbsd.org 2001/06/23 05:26:02
+     [key.c]
+     handle sigature of size 0 (some broken clients send this).
+   - deraadt@cvs.openbsd.org 2001/06/23 05:57:09
+     [sftp.1 sftp-server.8 ssh-keygen.1]
+     ok, tmac is now fixed
+   - markus@cvs.openbsd.org 2001/06/23 06:41:10
+     [ssh-keygen.c]
+     try to decode ssh-3.0.0 private rsa keys
+     (allow migration to openssh, not vice versa), #910
+   - itojun@cvs.openbsd.org 2001/06/23 15:12:20
+     [auth1.c auth2.c auth2-chall.c authfd.c authfile.c auth-rhosts.c
+      canohost.c channels.c cipher.c clientloop.c deattack.c dh.c
+      hostfile.c kex.c kexdh.c kexgex.c key.c nchan.c packet.c radix.c
+      readpass.c scp.c servconf.c serverloop.c session.c sftp.c
+      sftp-client.c sftp-glob.c sftp-int.c sftp-server.c ssh-add.c
+      ssh-agent.c ssh.c sshconnect1.c sshconnect2.c sshconnect.c sshd.c
+      ssh-keygen.c ssh-keyscan.c]
+     more strict prototypes.  raise warning level in Makefile.inc.
+     markus ok'ed
+     TODO; cleanup headers
+   - markus@cvs.openbsd.org 2001/06/23 17:05:22
+     [ssh-keygen.c]
+     fix import for (broken?) ssh.com/f-secure private keys
+     (i tested > 1000 RSA keys)
+   - itojun@cvs.openbsd.org 2001/06/23 17:48:18
+     [sftp.1 ssh.1 sshd.8 ssh-keyscan.1]
+     kill whitespace at EOL.
+   - markus@cvs.openbsd.org 2001/06/23 19:12:43
+     [sshd.c]
+     pidfile/sigterm race; bbraun@synack.net
+   - markus@cvs.openbsd.org 2001/06/23 22:37:46
+     [sshconnect1.c]
+     consistent with ssh2: skip key if empty passphrase is entered,
+     retry num_of_passwd_prompt times if passphrase is wrong. ok fgsch@
+   - markus@cvs.openbsd.org 2001/06/24 05:25:10
+     [auth-options.c match.c match.h]
+     move ip+hostname check to match.c
+   - markus@cvs.openbsd.org 2001/06/24 05:35:33
+     [readpass.c readpass.h ssh-add.c sshconnect2.c ssh-keygen.c]
+     switch to readpassphrase(3)
+     2.7/8-stable needs readpassphrase.[ch] from libc
+   - markus@cvs.openbsd.org 2001/06/24 05:47:13
+     [sshconnect2.c]
+     oops, missing format string
+   - markus@cvs.openbsd.org 2001/06/24 17:18:31
+     [ttymodes.c]
+     passing modes works fine: debug2->3
+ - (djm) -Wall fix for session.c
+ - (djm) Bring in readpassphrase() from OpenBSD libc. Compiles OK on Linux and
+   Solaris
+
+20010622
+ - (stevesk) handle systems without pw_expire and pw_change.
+
+20010621
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/06/16 08:49:38
+     [misc.c]
+     typo; dunlap@apl.washington.edu
+   - markus@cvs.openbsd.org 2001/06/16 08:50:39
+     [channels.h]
+     bad //-style comment; thx to stevev@darkwing.uoregon.edu
+   - markus@cvs.openbsd.org 2001/06/16 08:57:35
+     [scp.c]
+     no stdio or exit() in signal handlers.
+   - markus@cvs.openbsd.org 2001/06/16 08:58:34
+     [misc.c]
+     copy pw_expire and pw_change, too.
+   - markus@cvs.openbsd.org 2001/06/19 12:34:09
+     [session.c]
+     cleanup forced command handling, from dwd@bell-labs.com
+   - markus@cvs.openbsd.org 2001/06/19 14:09:45
+     [session.c sshd.8]
+     disable x11-fwd if use_login is enabled; from lukem@wasabisystems.com
+   - markus@cvs.openbsd.org 2001/06/19 15:40:45
+     [session.c]
+     allocate and free at the same level.
+   - markus@cvs.openbsd.org 2001/06/20 13:56:39
+     [channels.c channels.h clientloop.c packet.c serverloop.c]
+     move from channel_stop_listening to channel_free_all,
+     call channel_free_all before calling waitpid() in serverloop.
+     fixes the utmp handling; report from Lutz.Jaenicke@aet.TU-Cottbus.DE
+
+20010615
+ - (stevesk) don't set SA_RESTART and set SIGCHLD to SIG_DFL
+   around grantpt().
+ - (stevesk) update TODO: STREAMS pty systems don't call vhangup() now
+
+20010614
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/06/13 09:10:31
+     [session.c]
+     typo, use pid not s->pid, mstone@cs.loyola.edu
+
+20010613
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/06/12 10:58:29
+     [session.c]
+     merge session_free into session_close()
+     merge pty_cleanup_proc into session_pty_cleanup()
+   - markus@cvs.openbsd.org 2001/06/12 16:10:38
+     [session.c]
+     merge ssh1/ssh2 tty msg parse and alloc code
+   - markus@cvs.openbsd.org 2001/06/12 16:11:26
+     [packet.c]
+     do not log() packet_set_maxsize
+   - markus@cvs.openbsd.org 2001/06/12 21:21:29
+     [session.c]
+     remove xauth-cookie-in-tmp handling. use default $XAUTHORITY, since
+     we do already trust $HOME/.ssh
+     you can use .ssh/sshrc and .ssh/environment if you want to customize
+     the location of the xauth cookies
+   - markus@cvs.openbsd.org 2001/06/12 21:30:57
+     [session.c]
+     unused
+
+20010612
+ - scp.c ID update (upstream synced vfsprintf() from us)
+ - OpenBSD CVS Sync
+  - markus@cvs.openbsd.org 2001/06/10 11:29:20
+     [dispatch.c]
+     we support rekeying
+     protocol errors are fatal.
+   - markus@cvs.openbsd.org 2001/06/11 10:18:24
+     [session.c]
+     reset pointer to NULL after xfree(); report from solar@openwall.com
+   - markus@cvs.openbsd.org 2001/06/11 16:04:38
+     [sshd.8]
+     typo; bdubreuil@crrel.usace.army.mil
+
+20010611
+ - (bal) NeXT/MacOS X lack libgen.h and dirname().  Patch by Mark Miller
+   <markm@swoon.net>
+ - (bal) Handle broken krb4 issues on Solaris with multiple defined u_*_t
+   types.  Patch by Jan IVEN <Jan.Iven@cern.ch>
+ - (bal) Fixed Makefile.in so that 'configure; make install' works.
+
+20010610
+ - (bal) Missed two files in major resync.  auth-bsdauth.c and auth-skey.c
+
+20010609
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/30 12:55:13
+     [auth-options.c auth2.c channels.c channels.h clientloop.c nchan.c
+      packet.c serverloop.c session.c ssh.c ssh1.h]
+     channel layer cleanup: merge header files and split .c files
+   - markus@cvs.openbsd.org 2001/05/30 15:20:10
+     [ssh.c]
+     merge functions, simplify.
+   - markus@cvs.openbsd.org 2001/05/31 10:30:17
+     [auth-options.c auth2.c channels.c channels.h clientloop.c nchan.c
+      packet.c serverloop.c session.c ssh.c]
+     undo the .c file split, just merge the header and keep the cvs
+     history
+ - (bal) Channels.c and Channels.h -- "Merge Functions, simplify" (draged
+   out of ssh Attic)
+ - (bal) Ooops.. nchan.c (and remove nchan.h) resync from OpenBSD ssh
+   Attic.
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/31 13:08:04
+     [sshd_config]
+     group options and add some more comments
+   - markus@cvs.openbsd.org 2001/06/03 14:55:39
+     [channels.c channels.h session.c]
+     use fatal_register_cleanup instead of atexit, sync with x11 authdir
+     handling
+   - markus@cvs.openbsd.org 2001/06/03 19:36:44
+     [ssh-keygen.1]
+     1-2 bits of entrophy per character (not per word), ok stevesk@
+   - markus@cvs.openbsd.org 2001/06/03 19:38:42
+     [scp.c]
+     pass -v to ssh; from slade@shore.net
+   - markus@cvs.openbsd.org 2001/06/03 20:06:11
+     [auth2-chall.c]
+     the challenge response device decides how to handle non-existing
+     users.
+     -> fake challenges for skey and cryptocard
+   - markus@cvs.openbsd.org 2001/06/04 21:59:43
+     [channels.c channels.h session.c]
+     switch uid when cleaning up tmp files and sockets; reported by
+     zen-parse@gmx.net on bugtraq
+   - markus@cvs.openbsd.org 2001/06/04 23:07:21
+     [clientloop.c serverloop.c sshd.c]
+     set flags in the signal handlers, do real work in the main loop,
+     ok provos@
+   - markus@cvs.openbsd.org 2001/06/04 23:16:16
+     [session.c]
+     merge ssh1/2 x11-fwd setup, create listener after tmp-dir
+   - pvalchev@cvs.openbsd.org 2001/06/05 05:05:39
+     [ssh-keyscan.1 ssh-keyscan.c]
+     License clarification from David Mazieres, ok deraadt@
+   - markus@cvs.openbsd.org 2001/06/05 10:24:32
+     [channels.c]
+     don't delete the auth socket in channel_stop_listening()
+     auth_sock_cleanup_proc() will take care of this.
+   - markus@cvs.openbsd.org 2001/06/05 16:46:19
+     [session.c]
+     let session_close() delete the pty.  deny x11fwd if xauthfile is set.
+   - markus@cvs.openbsd.org 2001/06/06 23:13:54
+     [ssh-dss.c ssh-rsa.c]
+     cleanup, remove old code
+   - markus@cvs.openbsd.org 2001/06/06 23:19:35
+     [ssh-add.c]
+     remove debug message; Darren.Moffat@eng.sun.com
+   - markus@cvs.openbsd.org 2001/06/07 19:57:53
+     [auth2.c]
+     style is used for bsdauth.
+     disconnect on user/service change (ietf-drafts)
+   - markus@cvs.openbsd.org 2001/06/07 20:23:05
+     [authfd.c authfile.c channels.c kexdh.c kexgex.c packet.c ssh.c
+      sshconnect.c sshconnect1.c]
+     use xxx_put_cstring()
+   - markus@cvs.openbsd.org 2001/06/07 22:25:02
+     [session.c]
+     don't overwrite errno
+     delay deletion of the xauth cookie
+   - markus@cvs.openbsd.org 2001/06/08 15:25:40
+     [includes.h pathnames.h readconf.c servconf.c]
+     move the path for xauth to pathnames.h
+ - (bal) configure.in fix for Tru64 (forgeting to reset $LIB)
+ - (bal) ANSIify strmode()
+ - (bal) --with-catman should be --with-mantype patch by Dave
+   Dykstra <dwd@bell-labs.com>
+
+20010606
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/17 21:34:15
+     [ssh.1]
+     no spaces in PreferredAuthentications;
+     meixner@rbg.informatik.tu-darmstadt.de
+   - markus@cvs.openbsd.org 2001/05/18 14:13:29
+     [auth-chall.c auth.h auth1.c auth2-chall.c auth2.c readconf.c
+      readconf.h servconf.c servconf.h sshconnect1.c sshconnect2.c sshd.c]
+     improved kbd-interactive support. work by per@appgate.com and me
+   - djm@cvs.openbsd.org 2001/05/19 00:36:40
+     [session.c]
+     Disable X11 forwarding if xauth binary is not found. Patch from Nalin
+     Dahyabhai <nalin@redhat.com>; ok markus@
+   - markus@cvs.openbsd.org 2001/05/19 16:05:41
+     [scp.c]
+     ftruncate() instead of open()+O_TRUNC like rcp.c does
+     allows scp /path/to/file localhost:/path/to/file
+   - markus@cvs.openbsd.org 2001/05/19 16:08:43
+     [sshd.8]
+     sort options; Matthew.Stier@fnc.fujitsu.com
+   - markus@cvs.openbsd.org 2001/05/19 16:32:16
+     [ssh.1 sshconnect2.c]
+     change preferredauthentication order to
+        publickey,hostbased,password,keyboard-interactive
+     document that hostbased defaults to no, document order
+   - markus@cvs.openbsd.org 2001/05/19 16:46:19
+     [ssh.1 sshd.8]
+     document MACs defaults with .Dq
+   - stevesk@cvs.openbsd.org 2001/05/19 19:43:57
+     [misc.c misc.h servconf.c sshd.8 sshd.c]
+     sshd command-line arguments and configuration file options that
+     specify time may be expressed using a sequence of the form:
+     time[qualifier], where time is a positive integer value and qualifier
+     is one of the following:
+         <none>,s,m,h,d,w
+     Examples:
+         600     600 seconds (10 minutes)
+         10m     10 minutes
+         1h30m   1 hour 30 minutes (90 minutes)
+     ok markus@
+   - stevesk@cvs.openbsd.org 2001/05/19 19:57:09
+     [channels.c]
+     typo in error message
+   - markus@cvs.openbsd.org 2001/05/20 17:20:36
+     [auth-rsa.c auth.c auth.h auth2.c servconf.c servconf.h sshd.8
+      sshd_config]
+     configurable authorized_keys{,2} location; originally from peter@;
+     ok djm@
+   - markus@cvs.openbsd.org 2001/05/24 11:12:42
+     [auth.c]
+     fix comment; from jakob@
+   - stevesk@cvs.openbsd.org 2001/05/24 18:57:53
+     [clientloop.c readconf.c ssh.c ssh.h]
+     don't perform escape processing when ``EscapeChar none''; ok markus@
+   - markus@cvs.openbsd.org 2001/05/25 14:37:32
+     [ssh-keygen.c]
+     use -P for -e and -y, too.
+   - markus@cvs.openbsd.org 2001/05/28 08:04:39
+     [ssh.c]
+     fix usage()
+   - markus@cvs.openbsd.org 2001/05/28 10:08:55
+     [authfile.c]
+     key_load_private: set comment to filename for PEM keys
+   - markus@cvs.openbsd.org 2001/05/28 22:51:11
+     [cipher.c cipher.h]
+     simpler 3des for ssh1
+   - markus@cvs.openbsd.org 2001/05/28 23:14:49
+     [channels.c channels.h nchan.c]
+     undo broken channel fix and try a different one. there
+     should be still some select errors...
+   - markus@cvs.openbsd.org 2001/05/28 23:25:24
+     [channels.c]
+     cleanup, typo
+   - markus@cvs.openbsd.org 2001/05/28 23:58:35
+     [packet.c packet.h sshconnect.c sshd.c]
+     remove some lines, simplify.
+   - markus@cvs.openbsd.org 2001/05/29 12:31:27
+     [authfile.c]
+     typo
+
+20010528
+ - (tim) [conifgure.in] add setvbuf test needed for sftp-int.c
+   Patch by Corinna Vinschen <vinschen@redhat.com>
+
+20010517
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/12 19:53:13
+     [sftp-server.c]
+     readlink does not NULL-terminate; mhe@home.se
+   - deraadt@cvs.openbsd.org 2001/05/15 22:04:01
+     [ssh.1]
+     X11 forwarding details improved
+   - markus@cvs.openbsd.org 2001/05/16 20:51:57
+     [authfile.c]
+     return comments for private pem files, too; report from nolan@naic.edu
+   - markus@cvs.openbsd.org 2001/05/16 21:53:53
+     [clientloop.c]
+     check for open sessions before we call select(); fixes the x11 client
+     bug reported by bowman@math.ualberta.ca
+   - markus@cvs.openbsd.org 2001/05/16 22:09:21
+     [channels.c nchan.c]
+     more select() error fixes (don't set rfd/wfd to -1).
+ - (bal) Enabled USE_PIPES for Cygwin on Corinna Vinschen <vinschen@redhat.com>
+ - (bal) Corrected on_exit() emulation via atexit().
+
+20010512
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/11 14:59:56
+     [clientloop.c misc.c misc.h]
+     add unset_nonblock for stdout/err flushing in client_loop().
+ - (bal) Patch to partial sync up contrib/solaris/ packaging software.
+   Patch by pete <ninjaz@webexpress.com>
+
+20010511
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/09 22:51:57
+     [channels.c]
+     fix -R for protocol 2, noticed by greg@nest.cx.
+     bug was introduced with experimental dynamic forwarding.
+   - markus@cvs.openbsd.org 2001/05/09 23:01:31
+     [rijndael.h]
+     fix prototype; J.S.Peatfield@damtp.cam.ac.uk
+
+20010509
+  - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/06 21:23:31
+     [cli.c]
+     cli_read() fails to catch SIGINT + overflow; from obdb@zzlevo.net
+   - markus@cvs.openbsd.org 2001/05/08 19:17:31
+     [channels.c serverloop.c clientloop.c]
+     adds correct error reporting to async connect()s
+     fixes the server-discards-data-before-connected-bug found by
+     onoe@sm.sony.co.jp
+   - mouring@cvs.openbsd.org 2001/05/08 19:45:25
+     [misc.c misc.h scp.c sftp.c]
+     Use addargs() in sftp plus some clean up of addargs().  OK Markus
+   - markus@cvs.openbsd.org 2001/05/06 21:45:14
+     [clientloop.c]
+     use atomicio for flushing stdout/stderr bufs. thanks to
+     jbw@izanami.cee.hw.ac.uk
+   - markus@cvs.openbsd.org 2001/05/08 22:48:07
+     [atomicio.c]
+     no need for xmalloc.h, thanks to espie@
+ - (bal) UseLogin patch for Solaris/UNICOS.  Patch by Wayne Davison
+   <wayne@blorf.net>
+ - (bal) ./configure support to disable SIA on OSF1.  Patch by
+   Chris Adams <cmadams@hiwaay.net>
+ - (bal) Updates from the Sony NEWS-OS platform by NAKAJI Hiroyuki
+   <nakaji@tutrp.tut.ac.jp>
+
+20010508
+ - (bal) Fixed configure test for USE_SIA.
+
+20010506
+ - (djm) Update config.guess and config.sub with latest versions (from
+   ftp://ftp.gnu.org/gnu/config/) to allow configure on ia64-hpux.
+   Suggested by Jason Mader <jason@ncac.gwu.edu>
+ - (bal) White Space and #ifdef sync with OpenBSD
+ - (bal) Add 'seed_rng()' to ssh-add.c
+ - (bal) CVS ID updates for readpass.c, readpass.h, cli.c, and cli.h
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/05/05 13:42:52
+     [sftp.1 ssh-add.1 ssh-keygen.1]
+     typos, grammar
+
+20010505
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/05/04 14:21:56
+     [ssh.1 sshd.8]
+     typos
+   - markus@cvs.openbsd.org 2001/05/04 14:34:34
+     [channels.c]
+     channel_new() reallocs channels[], we cannot use Channel *c after
+     calling channel_new(), XXX fix this in the future...
+   - markus@cvs.openbsd.org 2001/05/04 23:47:34
+     [channels.c channels.h clientloop.c nchan.c nchan.h serverloop.c ssh.c]
+     move to Channel **channels (instead of Channel *channels), fixes realloc
+     problems.  channel_new now returns a Channel *, favour Channel * over
+     channel id.  remove old channel_allocate interface.
+
+20010504
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/05/03 15:07:39
+     [channels.c]
+     typo in debug() string
+   - markus@cvs.openbsd.org 2001/05/03 15:45:15
+     [session.c]
+     exec shell -c /bin/sh .ssh/sshrc, from abartlet@pcug.org.au
+   - stevesk@cvs.openbsd.org 2001/05/03 21:43:01
+     [servconf.c]
+     remove "\n" from fatal()
+   - mouring@cvs.openbsd.org 2001/05/03 23:09:53
+     [misc.c misc.h scp.c sftp.c]
+     Move colon() and cleanhost() to misc.c where I should I have put it in
+     the first place
+ - (bal) Updated Cygwin README by Corinna Vinschen <vinschen@redhat.com>
+ - (bal) Avoid socket file security issues in ssh-agent for Cygwin.
+   Patch by Egor Duda <deo@logos-m.ru>
+
+20010503
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/05/02 16:41:20
+     [ssh-add.c]
+     fix prompt for ssh-add.
+
+20010502
+ - OpenBSD CVS Sync
+   - mouring@cvs.openbsd.org 2001/05/02 01:25:39
+     [readpass.c]
+     Put the 'const' back into ssh_askpass() function.  Pointed out
+     by Mark Miller <markm@swoon.net>.  OK Markus
+
+20010501
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/30 11:18:52
+     [readconf.c readconf.h ssh.1 ssh.c sshconnect.c]
+     implement 'ssh -b bind_address' like 'telnet -b'
+   - markus@cvs.openbsd.org 2001/04/30 15:50:46
+     [compat.c compat.h kex.c]
+     allow interop with weaker key generation used by ssh-2.0.x, x < 10
+   - markus@cvs.openbsd.org 2001/04/30 16:02:49
+     [compat.c]
+     ssh-2.0.10 has the weak-key-bug, too.
+ - (tim) [contrib/caldera/openssh.spec] add Requires line for Caldera 3.1
+
+20010430
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/29 18:32:52
+     [serverloop.c]
+     fix whitespace
+   - markus@cvs.openbsd.org 2001/04/29 19:16:52
+     [channels.c clientloop.c compat.c compat.h serverloop.c]
+     more ssh.com-2.0.x bug-compat; from per@appgate.com
+ - (tim) New version of mdoc2man.pl from Mark D. Roth <roth+openssh@feep.net>
+ - (djm) Add .cvsignore files, suggested by Wayne Davison <wayne@blorf.net>
+
+20010429
+ - (bal) Updated INSTALL.  PCRE moved to a new place.
+ - (djm) Release OpenSSH-2.9p1
+
+20010427
+ - (bal) Fixed uidswap.c so it should work on non-posix complient systems.
+   patch based on 2.5.2 version by djm.
+ - (bal) Build manpages and config files once unless changed.  Patch by
+   Carson Gaspar <carson@taltos.org>
+ - (bal) arpa/nameser.h does not exist on Cygwin.  Patch by Corinna
+   Vinschen <vinschen@redhat.com>
+ - (bal) Add /etc/sysconfig/sshd support to redhat's sshd.init. Patch by
+   Pekka Savola <pekkas@netcore.fi>
+ - (bal) Cygwin lacks setgroups() API.  Patch by Corinna Vinschen
+   <vinschen@redhat.com>
+ - (bal) version.h synced, RPM specs updated for 2.9
+ - (tim) update contrib/caldera files with what Caldera is using.
+   <sps@caldera.de>
+
+20010425
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/23 21:57:07
+     [ssh-keygen.1 ssh-keygen.c]
+     allow public key for -e, too
+   - markus@cvs.openbsd.org 2001/04/23 22:14:13
+     [ssh-keygen.c]
+     remove debug
+ - (bal) Whitespace resync w/ OpenBSD for uidswap.c
+ - (djm) Add new server configuration directive 'PAMAuthenticationViaKbdInt'
+   (default: off), implies KbdInteractiveAuthentication. Suggestion from
+   markus@
+ - (djm) Include crypt.h if available in auth-passwd.c
+ - tim@mindrot.org 2001/04/25 21:38:01 [configure.in]
+   man page detection fixes for SCO
+
+20010424
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/22 23:58:36
+     [ssh-keygen.1 ssh.1 sshd.8]
+     document hostbased and other cleanup
+ - (stevesk) start_pam() doesn't use DNS now for sshd -u0.
+ - (stevesk) auth-pam.c: use PERMIT_NO_PASSWD
+ - (bal) sys/queue.h is bogus for NCR platform.  Patch by Daniel Carroll
+   <dan@mesastate.edu>
+ - (bal) Fixed contrib/postinstall.in.  Patch by wsanders@wsanders.net
+
+20010422
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/20 16:32:22
+     [uidswap.c]
+     set non-privileged gid before uid; tholo@ and deraadt@
+   - mouring@cvs.openbsd.org 2001/04/21 00:55:57
+     [sftp.1]
+     Spelling
+   - djm@cvs.openbsd.org 2001/04/22 08:13:30
+     [ssh.1]
+     typos spotted by stevesk@; ok deraadt@
+   - markus@cvs.openbsd.org 2001/04/22 12:34:05
+     [scp.c]
+     scp > 2GB; niles@scyld.com; ok deraadt@, djm@
+   - markus@cvs.openbsd.org 2001/04/22 13:25:37
+     [ssh-keygen.1 ssh-keygen.c]
+     rename arguments -x -> -e (export key), -X -> -i (import key)
+     xref draft-ietf-secsh-publickeyfile-01.txt
+   - markus@cvs.openbsd.org 2001/04/22 13:32:27
+     [sftp-server.8 sftp.1 ssh.1 sshd.8]
+     xref draft-ietf-secsh-*
+   - markus@cvs.openbsd.org 2001/04/22 13:41:02
+     [ssh-keygen.1 ssh-keygen.c]
+     style, noted by stevesk; sort flags in usage
+
+20010421
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2001/04/20 07:17:51
+     [clientloop.c ssh.1]
+     Split out and improve escape character documentation, mention ~R in
+     ~? help text; ok markus@
+ - Update RPM spec files for CVS version.h
+ - (stevesk) set the default PAM service name to __progname instead
+   of the hard-coded value "sshd"; from Mark D. Roth <roth@feep.net>
+ - (stevesk) document PAM service name change in INSTALL
+ - tim@mindrot.org 2001/04/21 14:25:57 [Makefile.in configure.in]
+   fix perl test, fix nroff test, fix Makefile to build outside source tree
+
+20010420
+ - OpenBSD CVS Sync
+   - ian@cvs.openbsd.org 2001/04/18 16:21:05
+     [ssh-keyscan.1]
+     Fix typo reported in PR/1779
+   - markus@cvs.openbsd.org 2001/04/18 21:57:42
+     [readpass.c ssh-add.c]
+     call askpass from ssh, too, based on work by roth@feep.net, ok deraadt
+   - markus@cvs.openbsd.org 2001/04/18 22:03:45
+     [auth2.c sshconnect2.c]
+     use FDQN with trailing dot in the hostbased auth packets, ok deraadt@
+   - markus@cvs.openbsd.org 2001/04/18 22:48:26
+     [auth2.c]
+     no longer const
+   - markus@cvs.openbsd.org 2001/04/18 23:43:26
+     [auth2.c compat.c sshconnect2.c]
+     more ssh v2 hostbased-auth interop: ssh.com >= 2.1.0 works now
+     (however the 2.1.0 server seems to work only if debug is enabled...)
+   - markus@cvs.openbsd.org 2001/04/18 23:44:51
+     [authfile.c]
+     error->debug; noted by fries@
+   - markus@cvs.openbsd.org 2001/04/19 00:05:11
+     [auth2.c]
+     use local variable, no function call needed.
+     (btw, hostbased works now with ssh.com >= 2.0.13)
+  - (bal) Put scp-common.h back into scp.c (it exists in the upstream
+    tree) pointed out by Tom Holroyd <tomh@po.crl.go.jp>
+
+20010418
+  - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/17 19:34:25
+     [session.c]
+     move auth_approval to do_authenticated().
+     do_child(): nuke hostkeys from memory
+     don't source .ssh/rc for subsystems.
+   - markus@cvs.openbsd.org 2001/04/18 14:15:00
+     [canohost.c]
+     debug->debug3
+  - (bal) renabled 'catman-do:' and fixed it.  So now catman pages should
+    be working again.
+  - (bal) Makfile day... Cleaned up multiple mantype support (Patch by
+    Mark D. Roth <roth+openssh@feep.net>), and fixed PIDDIR support.
+
+20010417
+  - (bal) Add perl5 check for HP/UX, Removed GNUness from Makefile.in
+    and temporary commented out 'catman-do:' since it is broken.  Patches
+    for the first two by Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+  - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/04/16 08:26:04
+     [key.c]
+     better safe than sorry in later mods; yongari@kt-is.co.kr
+   - markus@cvs.openbsd.org 2001/04/17 08:14:01
+     [sshconnect1.c]
+     check for key!=NULL, thanks to costa
+   - markus@cvs.openbsd.org 2001/04/17 09:52:48
+     [clientloop.c]
+     handle EINTR/EAGAIN on read; ok deraadt@
+   - markus@cvs.openbsd.org 2001/04/17 10:53:26
+     [key.c key.h readconf.c readconf.h ssh.1 sshconnect2.c]
+     add HostKeyAlgorithms; based on patch from res@shore.net; ok provos@
+   - markus@cvs.openbsd.org 2001/04/17 12:55:04
+     [channels.c ssh.c]
+     undo socks5 and https support since they are not really used and
+     only bloat ssh.  remove -D from usage(), since '-D' is experimental.
+
+20010416
+  - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/04/15 01:35:22
+     [ttymodes.c]
+     fix comments
+   - markus@cvs.openbsd.org 2001/04/15 08:43:47
+     [dh.c sftp-glob.c sftp-glob.h sftp-int.c sshconnect2.c sshd.c]
+     some unused variable and typos; from tomh@po.crl.go.jp
+   - markus@cvs.openbsd.org 2001/04/15 16:58:03
+     [authfile.c ssh-keygen.c sshd.c]
+     don't use errno for key_{load,save}_private; discussion w/ solar@openwall
+   - markus@cvs.openbsd.org 2001/04/15 17:16:00
+     [clientloop.c]
+     set stdin/out/err to nonblocking in SSH proto 1, too. suggested by ho@
+     should fix some of the blocking problems for rsync over SSH-1
+   - stevesk@cvs.openbsd.org 2001/04/15 19:41:21
+     [sshd.8]
+     some ClientAlive cleanup; ok markus@
+   - stevesk@cvs.openbsd.org 2001/04/15 21:28:35
+     [readconf.c servconf.c]
+     use fatal() or error() vs. fprintf(); ok markus@
+ - (djm) Convert mandoc manpages to man automatically. Patch from Mark D.
+   Roth <roth+openssh@feep.net>
+ - (bal) CVS ID fix up and slight manpage fix from OpenBSD tree.
+  - (djm) OpenBSD CVS Sync
+   - mouring@cvs.openbsd.org 2001/04/16 02:31:44
+     [scp.c sftp.c]
+     IPv6 support for sftp (which I bungled in my last patch) which is
+     borrowed from scp.c.  Thanks to Markus@ for pointing it out.
+   - deraadt@cvs.openbsd.org 2001/04/16 08:05:34
+     [xmalloc.c]
+     xrealloc dealing with ptr == nULL; mouring
+   - djm@cvs.openbsd.org 2001/04/16 08:19:31
+     [session.c]
+     Split motd and hushlogin checks into seperate functions, helps for
+     portable. From Chris Adams <cmadams@hiwaay.net>; ok markus@
+ - Fix OSF SIA support displaying too much information for quiet
+   logins and logins where access was denied by SIA. Patch from Chris Adams
+   <cmadams@hiwaay.net>
+
+20010415
+ - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/04/14 04:31:01
+     [ssh-add.c]
+     do not double free
+   - markus@cvs.openbsd.org 2001/04/14 16:17:14
+     [channels.c]
+     remove some channels that are not appropriate for keepalive.
+   - markus@cvs.openbsd.org 2001/04/14 16:27:57
+     [ssh-add.c]
+     use clear_pass instead of xfree()
+   - stevesk@cvs.openbsd.org 2001/04/14 16:33:20
+     [clientloop.c packet.h session.c ssh.c ttymodes.c ttymodes.h]
+     protocol 2 tty modes support; ok markus@
+   - stevesk@cvs.openbsd.org 2001/04/14 17:04:42
+     [scp.c]
+     'T' handling rcp/scp sync; ok markus@
+ - Missed sshtty.[ch] in Sync.
+
+20010414
+ - Sync with OpenBSD glob.c, strlcat.c and vis.c changes
+ - Cygwin sftp/sftp-server binary mode patch from Corinna Vinschen
+   <vinschen@redhat.com>
+ - OpenBSD CVS Sync
+   - beck@cvs.openbsd.org 2001/04/13 22:46:54
+     [channels.c channels.h servconf.c servconf.h serverloop.c sshd.8]
+     Add options ClientAliveInterval and ClientAliveCountMax to sshd.
+     This gives the ability to do a "keepalive" via the encrypted channel
+     which can't be spoofed (unlike TCP keepalives). Useful for when you want
+     to use ssh connections to authenticate people for something, and know
+     relatively quickly when they are no longer authenticated. Disabled
+     by default (of course). ok markus@
+
+20010413
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/12 14:29:09
+     [ssh.c]
+     show debug output during option processing, report from
+     pekkas@netcore.fi
+   - markus@cvs.openbsd.org 2001/04/12 19:15:26
+     [auth-rhosts.c auth.h auth2.c buffer.c canohost.c canohost.h
+      compat.c compat.h hostfile.c pathnames.h readconf.c readconf.h
+      servconf.c servconf.h ssh.c sshconnect.c sshconnect.h sshconnect1.c
+      sshconnect2.c sshd_config]
+     implement HostbasedAuthentication (= RhostRSAAuthentication for ssh v2)
+     similar to RhostRSAAuthentication unless you enable (the experimental)
+     HostbasedUsesNameFromPacketOnly option.  please test. :)
+   - markus@cvs.openbsd.org 2001/04/12 19:39:27
+     [readconf.c]
+     typo
+   - stevesk@cvs.openbsd.org 2001/04/12 20:09:38
+     [misc.c misc.h readconf.c servconf.c ssh.c sshd.c]
+     robust port validation; ok markus@ jakob@
+   - mouring@cvs.openbsd.org 2001/04/12 23:17:54
+     [sftp-int.c sftp-int.h sftp.1 sftp.c]
+     Add support for:
+        sftp [user@]host[:file [file]]  - Fetch remote file(s)
+        sftp [user@]host[:dir[/]]       - Start in remote dir/
+     OK deraadt@
+   - stevesk@cvs.openbsd.org 2001/04/13 01:26:17
+     [ssh.c]
+     missing \n in error message
+ - (bal) Added openbsd-compat/inet_ntop.[ch] since HP/UX (and others)
+   lack it.
+
+20010412
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/10 07:46:58
+     [channels.c]
+     cleanup socks4 handling
+   - itojun@cvs.openbsd.org 2001/04/10 09:13:22
+     [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8]
+     document id_rsa{.pub,}.  markus ok
+   - markus@cvs.openbsd.org 2001/04/10 12:15:23
+     [channels.c]
+     debug cleanup
+   - djm@cvs.openbsd.org 2001/04/11 07:06:22
+     [sftp-int.c]
+     'mget' and 'mput' aliases; ok markus@
+   - markus@cvs.openbsd.org 2001/04/11 10:59:01
+     [ssh.c]
+     use strtol() for ports, thanks jakob@
+   - markus@cvs.openbsd.org 2001/04/11 13:56:13
+     [channels.c ssh.c]
+     https-connect and socks5 support. i feel so bad.
+   - lebel@cvs.openbsd.org 2001/04/11 16:25:30
+     [sshd.8 sshd.c]
+     implement the -e option into sshd:
+      -e      When this option is specified, sshd will send the output to the
+              standard error instead of the system log.
+     markus@ OK.
+
+20010410
+ - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/04/08 20:52:55
+     [sftp.c]
+     do not modify an actual argv[] entry
+   - stevesk@cvs.openbsd.org 2001/04/08 23:28:27
+     [sshd.8]
+     spelling
+   - stevesk@cvs.openbsd.org 2001/04/09 00:42:05
+     [sftp.1]
+     spelling
+   - markus@cvs.openbsd.org 2001/04/09 15:12:23
+     [ssh-add.c]
+     passphrase caching: ssh-add tries last passphrase, clears passphrase if
+     not successful and after last try.
+     based on discussions with espie@, jakob@, ... and code from jakob@ and
+     wolfgang@wsrcc.com
+   - markus@cvs.openbsd.org 2001/04/09 15:19:49
+     [ssh-add.1]
+     ssh-add retries the last passphrase...
+   - stevesk@cvs.openbsd.org 2001/04/09 18:00:15
+     [sshd.8]
+     ListenAddress mandoc from aaron@
+
+20010409
+ - (stevesk) use setresgid() for setegid() if needed
+ - (stevesk) configure.in: typo
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/04/08 16:01:36
+     [sshd.8]
+     document ListenAddress addr:port
+   - markus@cvs.openbsd.org 2001/04/08 13:03:00
+     [ssh-add.c]
+     init pointers with NULL, thanks to danimal@danimal.org
+   - markus@cvs.openbsd.org 2001/04/08 11:27:33
+     [clientloop.c]
+     leave_raw_mode if ssh2 "session" is closed
+   - markus@cvs.openbsd.org 2001/04/06 21:00:17
+     [auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth2.c channels.c session.c
+      ssh.c sshconnect.c sshconnect.h uidswap.c uidswap.h]
+     do gid/groups-swap in addition to uid-swap, should help if /home/group
+     is chmod 750 + chgrp grp /home/group/, work be deraadt and me, thanks
+     to olar@openwall.com is comments.  we had many requests for this.
+   - markus@cvs.openbsd.org 2001/04/07 08:55:18
+     [buffer.c channels.c channels.h readconf.c ssh.c]
+     allow the ssh client act as a SOCKS4 proxy (dynamic local
+     portforwarding).  work by Dan Kaminsky <dankamin@cisco.com> and me.
+     thanks to Dan for this great patch: use 'ssh -D 1080 host' and make
+     netscape use localhost:1080 as a socks proxy.
+   - markus@cvs.openbsd.org 2001/04/08 11:24:33
+     [uidswap.c]
+     KNF
+
+20010408
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/04/06 22:12:47
+     [hostfile.c]
+     unused; typo in comment
+   - stevesk@cvs.openbsd.org 2001/04/06 22:25:25
+     [servconf.c]
+     in addition to:
+     ListenAddress host|ipv4_addr|ipv6_addr
+     permit:
+     ListenAddress [host|ipv4_addr|ipv6_addr]:port
+     ListenAddress host|ipv4_addr:port
+     sshd.8 updates coming.  ok markus@
+
+20010407
+ - (bal) CVS ID Resync of version.h
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/05 23:39:20
+     [serverloop.c]
+     keep the ssh session even if there is no active channel.
+     this is more in line with the protocol spec and makes
+        ssh -N -L 1234:server:110 host
+     more useful.
+     based on discussion with <mats@mindbright.se> long time ago
+     and recent mail from <res@shore.net>
+   - deraadt@cvs.openbsd.org 2001/04/06 16:46:59
+     [scp.c]
+     remove trailing / from source paths; fixes pr#1756
+
+20010406
+ - (stevesk) logintest.c: fix for systems without __progname
+ - (stevesk) Makefile.in: log.o is in libssh.a
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/05 10:00:06
+     [compat.c]
+     2.3.x does old  GEX, too; report jakob@
+   - markus@cvs.openbsd.org 2001/04/05 10:39:03
+     [compress.c compress.h packet.c]
+     reset compress state per direction when rekeying.
+   - markus@cvs.openbsd.org 2001/04/05 10:39:48
+     [version.h]
+     temporary version 2.5.4 (supports rekeying).
+     this is not an official release.
+   - markus@cvs.openbsd.org 2001/04/05 10:42:57
+     [auth-chall.c authfd.c channels.c clientloop.c kex.c kexgex.c key.c
+      mac.c packet.c serverloop.c sftp-client.c sftp-client.h sftp-glob.c
+      sftp-glob.h sftp-int.c sftp-server.c sftp.c ssh-keygen.c sshconnect.c
+      sshconnect2.c sshd.c]
+     fix whitespace: unexpand + trailing spaces.
+   - markus@cvs.openbsd.org 2001/04/05 11:09:17
+     [clientloop.c compat.c compat.h]
+     add SSH_BUG_NOREKEY and detect broken (=all old) openssh versions.
+   - markus@cvs.openbsd.org 2001/04/05 15:45:43
+     [ssh.1]
+     ssh defaults to protocol v2; from quisar@quisar.ambre.net
+   - stevesk@cvs.openbsd.org 2001/04/05 15:48:18
+     [canohost.c canohost.h session.c]
+     move get_remote_name_or_ip() to canohost.[ch]; for portable.  ok markus@
+   - markus@cvs.openbsd.org 2001/04/05 20:01:10
+     [clientloop.c]
+     for ~R print message if server does not support rekeying. (and fix ~R).
+   - markus@cvs.openbsd.org 2001/04/05 21:02:46
+     [buffer.c]
+     better error message
+   - markus@cvs.openbsd.org 2001/04/05 21:05:24
+     [clientloop.c ssh.c]
+     don't request a session for 'ssh -N', pointed out slade@shore.net
+
+20010405
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/04/04 09:48:35
+     [kex.c kex.h kexdh.c kexgex.c packet.c sshconnect2.c sshd.c]
+     don't sent multiple kexinit-requests.
+     send newkeys, block while waiting for newkeys.
+     fix comments.
+   - markus@cvs.openbsd.org 2001/04/04 14:34:58
+     [clientloop.c kex.c kex.h serverloop.c sshconnect2.c sshd.c]
+     enable server side rekeying + some rekey related clientup.
+     todo: we should not send any non-KEX messages after we send KEXINIT
+   - markus@cvs.openbsd.org 2001/04/04 15:50:55
+     [compat.c]
+     f-secure 1.3.2 does not handle IGNORE; from milliondl@ornl.gov
+   - markus@cvs.openbsd.org 2001/04/04 20:25:38
+     [channels.c channels.h clientloop.c kex.c kex.h serverloop.c
+      sshconnect2.c sshd.c]
+     more robust rekeying
+     don't send channel data after rekeying is started.
+   - markus@cvs.openbsd.org 2001/04/04 20:32:56
+     [auth2.c]
+     we don't care about missing bannerfiles; from tsoome@ut.ee, ok deraadt@
+   - markus@cvs.openbsd.org 2001/04/04 22:04:35
+     [kex.c kexgex.c serverloop.c]
+     parse full kexinit packet.
+     make server-side more robust, too.
+   - markus@cvs.openbsd.org 2001/04/04 23:09:18
+     [dh.c kex.c packet.c]
+     clear+free keys,iv for rekeying.
+     + fix DH mem leaks. ok niels@
+ - (stevesk) don't use vhangup() if defined(HAVE_DEV_PTMX); also removes
+    BROKEN_VHANGUP
+
+20010404
+ - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/04/02 17:32:23
+     [ssh-agent.1]
+     grammar; slade@shore.net
+   - stevesk@cvs.openbsd.org 2001/04/03 13:56:11
+     [sftp-glob.c ssh-agent.c ssh-keygen.c]
+     free() -> xfree()
+   - markus@cvs.openbsd.org 2001/04/03 19:53:29
+     [dh.c dh.h kex.c kex.h sshconnect2.c sshd.c]
+     move kex to kex*.c, used dispatch_set() callbacks for kex. should
+     make rekeying easier.
+   - todd@cvs.openbsd.org 2001/04/03 21:19:38
+     [ssh_config]
+     id_rsa1/2 -> id_rsa; ok markus@
+   - markus@cvs.openbsd.org 2001/04/03 23:32:12
+     [kex.c kex.h packet.c sshconnect2.c sshd.c]
+     undo parts of recent my changes: main part of keyexchange does not
+     need dispatch-callbacks, since application data is delayed until
+     the keyexchange completes (if i understand the drafts correctly).
+     add some infrastructure for re-keying.
+   - markus@cvs.openbsd.org 2001/04/04 00:06:54
+     [clientloop.c sshconnect2.c]
+     enable client rekeying
+        (1) force rekeying with ~R, or
+        (2) if the server requests rekeying.
+     works against ssh-2.0.12/2.0.13/2.1.0/2.2.0/2.3.0/2.3.1/2.4.0
+ - (bal) Oops.. Missed including kexdh.c and kexgex.c in OpenBSD sync.
+
+20010403
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/04/02 14:15:31
+     [sshd.8]
+     typo; ok markus@
+   - stevesk@cvs.openbsd.org 2001/04/02 14:20:23
+     [readconf.c servconf.c]
+     correct comment; ok markus@
+ - (stevesk) nchan.c: remove ostate checks and add EINVAL to
+    shutdown(SHUT_RD) error() bypass for HP-UX.
+
+20010402
+ - (stevesk) log.c openbsd sync; missing newlines
+ - (stevesk) sshpty.h openbsd sync; PTY_H -> SSHPTY_H
+
+20010330
+ - (djm) Another openbsd-compat/glob.c sync
+ - (djm) OpenBSD CVS Sync
+   - provos@cvs.openbsd.org 2001/03/28 21:59:41
+     [kex.c kex.h sshconnect2.c sshd.c]
+     forgot to include min and max params in hash, okay markus@
+   - provos@cvs.openbsd.org 2001/03/28 22:04:57
+     [dh.c]
+     more sanity checking on primes file
+   - markus@cvs.openbsd.org 2001/03/28 22:43:31
+     [auth.h auth2.c auth2-chall.c]
+     check auth_root_allowed for kbd-int auth, too.
+   - provos@cvs.openbsd.org 2001/03/29 14:24:59
+     [sshconnect2.c]
+     use recommended defaults
+   - stevesk@cvs.openbsd.org 2001/03/29 21:06:21
+     [sshconnect2.c sshd.c]
+     need to set both STOC and CTOS for SSH_BUG_BIGENDIANAES; ok markus@
+   - markus@cvs.openbsd.org 2001/03/29 21:17:40
+     [dh.c dh.h kex.c kex.h]
+     prepare for rekeying: move DH code to dh.c
+   - djm@cvs.openbsd.org 2001/03/29 23:42:01
+     [sshd.c]
+     Protocol 1 key regeneration log => verbose, some KNF; ok markus@
+
+20010329
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/03/26 15:47:59
+     [ssh.1]
+     document more defaults; misc. cleanup.  ok markus@
+   - markus@cvs.openbsd.org 2001/03/26 23:12:42
+     [authfile.c]
+     KNF
+   - markus@cvs.openbsd.org 2001/03/26 23:23:24
+     [rsa.c rsa.h ssh-agent.c ssh-keygen.c]
+     try to read private f-secure ssh v2 rsa keys.
+   - markus@cvs.openbsd.org 2001/03/27 10:34:08
+     [ssh-rsa.c sshd.c]
+     use EVP_get_digestbynid, reorder some calls and fix missing free.
+   - markus@cvs.openbsd.org 2001/03/27 10:57:00
+     [compat.c compat.h ssh-rsa.c]
+     some older systems use NID_md5 instead of NID_sha1 for RSASSA-PKCS1-v1_5
+     signatures in SSH protocol 2, ok djm@
+   - provos@cvs.openbsd.org 2001/03/27 17:46:50
+     [compat.c compat.h dh.c dh.h ssh2.h sshconnect2.c sshd.c version.h]
+     make dh group exchange more flexible, allow min and max group size,
+     okay markus@, deraadt@
+   - stevesk@cvs.openbsd.org 2001/03/28 19:56:23
+     [scp.c]
+     start to sync scp closer to rcp; ok markus@
+   - stevesk@cvs.openbsd.org 2001/03/28 20:04:38
+     [scp.c]
+     usage more like rcp and add missing -B to usage; ok markus@
+   - markus@cvs.openbsd.org 2001/03/28 20:50:45
+     [sshd.c]
+     call refuse() before close(); from olemx@ans.pl
+
+20010328
+ - (djm) Reorder tests and library inclusion for Krb4/AFS to try to
+   resolve linking conflicts with libcrypto. Report and suggested fix
+   from Holger Trapp <Holger.Trapp@Informatik.TU-Chemnitz.DE>
+ - (djm) Work around Solaris' broken struct dirent. Diagnosis and suggested
+   fix from Philippe Levan <levan@epix.net>
+ - (djm) Rework krbIV tests to get us closer to building on Redhat. Still
+   doesn't work because of conflicts between krbIV's and OpenSSL's des.h
+ - (djm) Sync openbsd-compat/glob.c
+
+20010327
+ - Attempt sync with sshlogin.c w/ OpenBSD (mainly CVS ID)
+ - Fix pointer issues in waitpid() and wait() replaces.  Patch by Lutz
+   Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2001/03/25 00:01:34
+     [session.c]
+     shorten; ok markus@
+   - stevesk@cvs.openbsd.org 2001/03/25 13:16:11
+     [servconf.c servconf.h session.c sshd.8 sshd_config]
+     PrintLastLog option; from chip@valinux.com with some minor
+     changes by me.  ok markus@
+   - markus@cvs.openbsd.org 2001/03/26 08:07:09
+     [authfile.c authfile.h ssh-add.c ssh-keygen.c ssh.c sshconnect.c
+      sshconnect.h sshconnect1.c sshconnect2.c sshd.c]
+     simpler key load/save interface, see authfile.h
+ - (djm) Reestablish PAM credentials (which can be supplemental group
+   memberships) after initgroups() blows them away. Report and suggested
+   fix from Nalin Dahyabhai <nalin@redhat.com>
+
+20010324
+ - Fixed permissions ssh-keyscan.  Thanks to Christopher Linn <celinn@mtu.edu>.
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2001/03/23 11:04:07
+     [compat.c compat.h sshconnect2.c sshd.c]
+     Compat for OpenSSH with broken Rijndael/AES. ok markus@
+   - markus@cvs.openbsd.org 2001/03/23 12:02:49
+     [auth1.c]
+     authctxt is now passed to do_authenticated
+   - markus@cvs.openbsd.org 2001/03/23 13:10:57
+     [sftp-int.c]
+     fix put, upload to _absolute_ path, ok djm@
+   - markus@cvs.openbsd.org 2001/03/23 14:28:32
+     [session.c sshd.c]
+     ignore SIGPIPE, restore in child, fixes x11-fwd crashes; with djm@
+ - (djm) Pull out our own SIGPIPE hacks
+
+20010323
+ - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/03/22 20:22:55
+     [sshd.c]
+     do not place linefeeds in buffer
+
+20010322
+ - (djm) Better AIX no tty fix, spotted by Gert Doering <gert@greenie.muc.de>
+ - (bal) version.c CVS ID resync
+ - (bal) auth-chall.c auth-passwd.c auth.h auth1.c auth2.c session.c CVS ID
+   resync
+ - (bal) scp.c CVS ID resync
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/20 19:10:16
+     [readconf.c]
+     default to SSH protocol version 2
+   - markus@cvs.openbsd.org 2001/03/20 19:21:21
+     [session.c]
+     remove unused arg
+   - markus@cvs.openbsd.org 2001/03/20 19:21:21
+     [session.c]
+     remove unused arg
+   - markus@cvs.openbsd.org 2001/03/21 11:43:45
+     [auth1.c auth2.c session.c session.h]
+     merge common ssh v1/2 code
+   - jakob@cvs.openbsd.org 2001/03/21 14:20:45
+     [ssh-keygen.c]
+     add -B flag to usage
+   - markus@cvs.openbsd.org 2001/03/21 21:06:30
+     [session.c]
+     missing init; from mib@unimelb.edu.au
+
+20010321
+ - (djm) Fix ttyname breakage for AIX and Tru64. Patch from Steve
+   VanDevender <stevev@darkwing.uoregon.edu>
+ - (djm) Make sure pam_retval is initialised on call to pam_end. Patch
+   from Solar Designer <solar@openwall.com>
+ - (djm) Don't loop forever when changing password via PAM. Patch
+   from Solar Designer <solar@openwall.com>
+ - (djm) Generate config files before build
+ - (djm) Correctly handle SIA and AIX when no tty present. Spotted and
+   suggested fix from Mike Battersby <mib@unimelb.edu.au>
+
+20010320
+ - (bal) glob.c update to added GLOB_LIMITS (OpenBSD CVS).
+ - (bal) glob.c update to set gl_pathv to NULL (OpenBSD CVS).
+ - (bal) Oops.  Missed globc.h change (OpenBSD CVS).
+ - (djm) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/19 17:07:23
+     [auth.c readconf.c]
+     undo /etc/shell and proto 2,1 change for openssh-2.5.2
+   - markus@cvs.openbsd.org 2001/03/19 17:12:10
+     [version.h]
+     version 2.5.2
+ - (djm) Update RPM spec version
+ - (djm) Release 2.5.2p1
+- tim@mindrot.org 2001/03/19 18:33:47 [defines.h]
+  change S_ISLNK macro to work for UnixWare 2.03
+- tim@mindrot.org 2001/03/19 20:45:11 [openbsd-compat/glob.c]
+  add get_arg_max(). Use sysconf() if ARG_MAX is not defined
+
+20010319
+ - (djm) Seed PRNG at startup, rather than waiting for arc4random calls to
+   do it implicitly.
+ - (djm) Add getusershell() functions from OpenBSD CVS
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/18 12:07:52
+     [auth-options.c]
+     ignore permitopen="host:port" if AllowTcpForwarding==no
+ - (djm) Make scp work on systems without 64-bit ints
+ - tim@mindrot.org 2001/03/18 18:28:39 [defines.h]
+   move HAVE_LONG_LONG_INT where it works
+ - (bal) Use 'NGROUPS' for NeXT Since 'MAX_NGROUPS' is wrapped up in -lposix
+   stuff.  Change suggested by Mark Miller <markm@swoon.net>
+ - (bal) Small fix to scp.  %lu vs %ld
+ - (bal) NeXTStep lacks S_ISLNK.  Plus split up S_IS*
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org     2001/03/19 03:52:51
+     [sftp-client.c]
+     Report ssh connection closing correctly; ok deraadt@
+   - deraadt@cvs.openbsd.org 2001/03/18 23:30:55
+     [compat.c compat.h sshd.c]
+     specifically version match on ssh scanners.  do not log scan
+     information to the console
+   - djm@cvs.openbsd.org      2001/03/19 12:10:17
+     [sshd.8]
+     Document permitopen authorized_keys option; ok markus@
+   - djm@cvs.openbsd.org     2001/03/19 05:49:52
+     [ssh.1]
+     document PreferredAuthentications option; ok markus@
+ - (bal) Minor NeXT fixed.  Forgot to #undef NGROUPS_MAX
+
+20010318
+ - (bal) Fixed scp type casing issue which causes "scp: protocol error:
+   size not delimited" fatal errors when tranfering.
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/17 17:27:59
+     [auth.c]
+     check /etc/shells, too
+ - tim@mindrot.org 2001/03/17 18:45:25 [compat.c]
+     openbsd-compat/fake-regex.h
+
+20010317
+ - Support usrinfo() on AIX. Based on patch from Gert Doering
+   <gert@greenie.muc.de>
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/15 15:05:59
+     [scp.c]
+     use %lld in printf, ok millert@/deraadt@; report from ssh@client.fi
+   - markus@cvs.openbsd.org 2001/03/15 22:07:08
+     [session.c]
+     pass Session to do_child + KNF
+   - djm@cvs.openbsd.org 2001/03/16 08:16:18
+     [sftp-client.c sftp-client.h sftp-glob.c sftp-int.c]
+     Revise globbing for get/put to be more shell-like. In particular,
+     "get/put file* directory/" now works. ok markus@
+   - markus@cvs.openbsd.org 2001/03/16 09:55:53
+     [sftp-int.c]
+     fix memset and whitespace
+   - markus@cvs.openbsd.org 2001/03/16 13:44:24
+     [sftp-int.c]
+     discourage strcat/strcpy
+   - markus@cvs.openbsd.org 2001/03/16 19:06:30
+     [auth-options.c channels.c channels.h serverloop.c session.c]
+     implement "permitopen" key option, restricts -L style forwarding to
+     to specified host:port pairs. based on work by harlan@genua.de
+ - Check for gl_matchc support in glob_t and fall back to the
+   openbsd-compat/glob.[ch] support if it does not exist.
+
+20010315
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/14 08:57:14
+     [sftp-client.c]
+     Wall
+   - markus@cvs.openbsd.org 2001/03/14 15:15:58
+     [sftp-int.c]
+     add version command
+   - deraadt@cvs.openbsd.org 2001/03/14 22:50:25
+     [sftp-server.c]
+     note no getopt()
+ - (stevesk) ssh-keyscan.c: specify "openbsd-compat/fake-queue.h"
+ - (bal) Cygwin README change by Corinna Vinschen <vinschen@redhat.com>
+
+20010314
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/13 17:34:42
+     [auth-options.c]
+     missing xfree, deny key on parse error; ok stevesk@
+   - djm@cvs.openbsd.org 2001/03/13 22:42:54
+     [sftp-client.c sftp-client.h sftp-glob.c sftp-glob.h sftp-int.c]
+     sftp client filename globbing for get, put, ch{mod,grp,own}. ok markus@
+ - (bal) Fix strerror() in bsd-misc.c
+ - (djm) Add replacement glob() from OpenBSD libc if the system glob is
+   missing or lacks the GLOB_ALTDIRFUNC extension
+ - (djm) Remove -I$(srcdir)/openbsd-compat from CFLAGS, refer to headers
+   relatively. Avoids conflict between glob.h and /usr/include/glob.h
+
+20010313
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/12 22:02:02
+     [key.c key.h ssh-add.c ssh-keygen.c sshconnect.c sshconnect2.c]
+     remove old key_fingerprint interface, s/_ex//
+
+20010312
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/11 13:25:36
+     [auth2.c key.c]
+     debug
+   - jakob@cvs.openbsd.org 2001/03/11 15:03:16
+     [key.c key.h]
+     add improved fingerprint functions. based on work by Carsten
+     Raskgaard <cara@int.tele.dk> and modified by me. ok markus@.
+   - jakob@cvs.openbsd.org 2001/03/11 15:04:16
+     [ssh-keygen.1 ssh-keygen.c]
+     print both md5, sha1 and bubblebabble fingerprints when using
+     ssh-keygen -l -v. ok markus@.
+   - jakob@cvs.openbsd.org 2001/03/11 15:13:09
+     [key.c]
+     cleanup & shorten some var names key_fingerprint_bubblebabble.
+   - deraadt@cvs.openbsd.org 2001/03/11 16:39:03
+     [ssh-keygen.c]
+     KNF, and SHA1 binary output is just creeping featurism
+ - tim@mindrot.org 2001/03/11 17:29:32 [configure.in]
+   test if snprintf() supports %ll
+   add /dev to search path for PRNGD/EGD socket
+   fix my mistake in USER_PATH test program
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/11 18:29:51
+     [key.c]
+     style+cleanup
+   - markus@cvs.openbsd.org 2001/03/11 22:33:24
+     [ssh-keygen.1 ssh-keygen.c]
+     remove -v again. use -B instead for bubblebabble. make -B consistent
+     with -l and make -B work with /path/to/known_hosts. ok deraadt@
+ - (djm) Bump portable version number for generating test RPMs
+ - (djm) Add "static_openssl" RPM build option, remove rsh build dependency
+ - (bal) Reorder includes in Makefile.
+
+20010311
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/10 12:48:27
+     [sshconnect2.c]
+     ignore nonexisting private keys; report rjmooney@mediaone.net
+   - deraadt@cvs.openbsd.org 2001/03/10 12:53:51
+     [readconf.c ssh_config]
+     default to SSH2, now that m68k runs fast
+   - stevesk@cvs.openbsd.org 2001/03/10 15:02:05
+     [ttymodes.c ttymodes.h]
+     remove unused sgtty macros; ok markus@
+   - deraadt@cvs.openbsd.org 2001/03/10 15:31:00
+     [compat.c compat.h sshconnect.c]
+     all known netscreen ssh versions, and older versions of OSU ssh cannot
+     handle password padding (newer OSU is fixed)
+ - tim@mindrot.org 2001/03/10 16:33:42 [configure.in Makefile.in sshd_config]
+   make sure $bindir is in USER_PATH so scp will work
+ - OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2001/03/10 17:51:04
+     [kex.c match.c match.h readconf.c readconf.h sshconnect2.c]
+     add PreferredAuthentications
+
+20010310
+ - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/03/09 03:14:39
+     [ssh-keygen.c]
+     create *.pub files with umask 0644, so that you can mv them to
+     authorized_keys
+   - deraadt@cvs.openbsd.org 2001/03/09 12:30:29
+     [sshd.c]
+     typo; slade@shore.net
+ - Removed log.o from sftp client.  Not needed.
+
+20010309
+ - OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2001/03/08 18:47:12
+     [auth1.c]
+     unused; ok markus@
+   - stevesk@cvs.openbsd.org 2001/03/08 20:44:48
+     [sftp.1]
+     spelling, cleanup; ok deraadt@
+   - markus@cvs.openbsd.org 2001/03/08 21:42:33
+     [compat.c compat.h readconf.h ssh.c sshconnect1.c sshconnect2.c]
+     implement client side of SSH2_MSG_USERAUTH_PK_OK (test public key ->
+     no need to do enter passphrase or do expensive sign operations if the
+     server does not accept key).
+
+20010308
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2001/03/07 10:11:23
+     [sftp-client.c sftp-client.h sftp-int.c sftp-server.c sftp.1 sftp.c sftp.h]
+     Support for new draft (draft-ietf-secsh-filexfer-01). New symlink handling
+     functions and small protocol change.
+   - markus@cvs.openbsd.org 2001/03/08 00:15:48
+     [readconf.c ssh.1]
+     turn off useprivilegedports by default. only rhost-auth needs
+     this. older sshd's may need this, too.
+ - (stevesk) Reliant Unix (SNI) needs HAVE_BOGUS_SYS_QUEUE_H;
+   Dirk Markwardt <D.Markwardt@tu-bs.de>
+
+20010307
+ - (bal) OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/03/06 06:11:18
+     [ssh-keyscan.c]
+     appease gcc
+   - deraadt@cvs.openbsd.org 2001/03/06 06:11:44
+     [sftp-int.c sftp.1 sftp.c]
+     sftp -b batchfile; mouring@etoh.eviladmin.org
+   - deraadt@cvs.openbsd.org 2001/03/06 15:10:42
+     [sftp.1]
+     order things
+   - deraadt@cvs.openbsd.org 2001/03/07 01:19:06
+     [ssh.1 sshd.8]
+     the name "secure shell" is boring, noone ever uses it
+   - deraadt@cvs.openbsd.org 2001/03/07 04:05:58
+     [ssh.1]
+     removed dated comment
+ - Cygwin contrib improvements from Corinna Vinschen <vinschen@redhat.com>
+
+20010306
+ - (bal) OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/03/05 14:28:47
+     [sshd.8]
+     alpha order; jcs@rt.fm
+   - stevesk@cvs.openbsd.org 2001/03/05 15:44:51
+     [servconf.c]
+     sync error message; ok markus@
+   - deraadt@cvs.openbsd.org 2001/03/05 15:56:16
+     [myproposal.h ssh.1]
+     switch to aes128-cbc/hmac-md5 by default in SSH2 -- faster;
+     provos & markus ok
+   - deraadt@cvs.openbsd.org 2001/03/05 16:07:15
+     [sshd.8]
+     detail default hmac setup too
+   - markus@cvs.openbsd.org 2001/03/05 17:17:21
+     [kex.c kex.h sshconnect2.c sshd.c]
+     generate a 2*need size (~300 instead of 1024/2048) random private
+     exponent during the DH key agreement. according to Niels (the great
+     german advisor) this is safe since /etc/primes contains strong
+     primes only.
+
+     References:
+             P. C. van Oorschot and M. J. Wiener, On Diffie-Hellman key
+             agreement with short exponents, In Advances in Cryptology
+             - EUROCRYPT'96, LNCS 1070, Springer-Verlag, 1996, pp.332-343.
+   - stevesk@cvs.openbsd.org 2001/03/05 17:40:48
+     [ssh.1]
+     more ssh_known_hosts2 documentation; ok markus@
+   - stevesk@cvs.openbsd.org 2001/03/05 17:58:22
+     [dh.c]
+     spelling
+   - deraadt@cvs.openbsd.org 2001/03/06 00:33:04
+     [authfd.c cli.c ssh-agent.c]
+     EINTR/EAGAIN handling is required in more cases
+   - millert@cvs.openbsd.org 2001/03/06 01:06:03
+     [ssh-keyscan.c]
+     Don't assume we wil get the version string all in one read().
+     deraadt@ OK'd
+   - millert@cvs.openbsd.org 2001/03/06 01:08:27
+     [clientloop.c]
+     If read() fails with EINTR deal with it the same way we treat EAGAIN
+
+20010305
+ - (bal) CVS ID touch up on sshpty.[ch] and sshlogin.[ch]
+ - (bal) CVS ID touch up on sftp-int.c
+ - (bal) CVS ID touch up on uuencode.c
+ - (bal) CVS ID touch up on auth2.c, serverloop.c, session.c & sshd.c
+ - (bal) OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2001/02/17 23:48:48
+     [sshd.8]
+     it's the OpenSSH one
+   - deraadt@cvs.openbsd.org 2001/02/21 07:37:04
+     [ssh-keyscan.c]
+     inline -> __inline__, and some indent
+   - deraadt@cvs.openbsd.org 2001/02/21 09:05:54
+     [authfile.c]
+     improve fd handling
+   - deraadt@cvs.openbsd.org 2001/02/21 09:12:56
+     [sftp-server.c]
+     careful with & and &&; markus ok
+   - stevesk@cvs.openbsd.org 2001/02/21 21:14:04
+     [ssh.c]
+     -i supports DSA identities now; ok markus@
+   - deraadt@cvs.openbsd.org 2001/02/22 04:29:37
+     [servconf.c]
+     grammar; slade@shore.net
+   - deraadt@cvs.openbsd.org 2001/02/22 06:43:55
+     [ssh-keygen.1 ssh-keygen.c]
+     document -d, and -t defaults to rsa1
+   - deraadt@cvs.openbsd.org 2001/02/22 08:03:51
+     [ssh-keygen.1 ssh-keygen.c]
+     bye bye -d
+   - deraadt@cvs.openbsd.org 2001/02/22 18:09:06
+     [sshd_config]
+     activate RSA 2 key
+   - markus@cvs.openbsd.org 2001/02/22 21:57:27
+     [ssh.1 sshd.8]
+     typos/grammar from matt@anzen.com
+   - markus@cvs.openbsd.org 2001/02/22 21:59:44
+     [auth.c auth.h auth1.c auth2.c misc.c misc.h ssh.c]
+     use pwcopy in ssh.c, too
+   - markus@cvs.openbsd.org 2001/02/23 15:34:53
+     [serverloop.c]
+     debug2->3
+   - markus@cvs.openbsd.org 2001/02/23 18:15:13
+     [sshd.c]
+     the random session key depends now on the session_key_int
+     sent by the 'attacker'
+             dig1 = md5(cookie|session_key_int);
+             dig2 = md5(dig1|cookie|session_key_int);
+             fake_session_key = dig1|dig2;
+     this change is caused by a mail from anakin@pobox.com
+     patch based on discussions with my german advisor niels@openbsd.org
+   - deraadt@cvs.openbsd.org 2001/02/24 10:37:55
+     [readconf.c]
+     look for id_rsa by default, before id_dsa
+   - deraadt@cvs.openbsd.org 2001/02/24 10:37:26
+     [sshd_config]
+     ssh2 rsa key before dsa key
+   - markus@cvs.openbsd.org 2001/02/27 10:35:27
+     [packet.c]
+     fix random padding
+   - markus@cvs.openbsd.org 2001/02/27 11:00:11
+     [compat.c]
+     support SSH-2.0-2.1 ; from Christophe_Moret@hp.com
+   - deraadt@cvs.openbsd.org 2001/02/28 05:34:28
+     [misc.c]
+     pull in protos
+   - deraadt@cvs.openbsd.org 2001/02/28 05:36:28
+     [sftp.c]
+     do not kill the subprocess on termination (we will see if this helps
+     things or hurts things)
+   - markus@cvs.openbsd.org 2001/02/28 08:45:39
+     [clientloop.c]
+     fix byte counts for ssh protocol v1
+   - markus@cvs.openbsd.org 2001/02/28 08:54:55
+     [channels.c nchan.c nchan.h]
+     make sure remote stderr does not get truncated.
+     remove closed fd's from the select mask.
+   - markus@cvs.openbsd.org 2001/02/28 09:57:07
+     [packet.c packet.h sshconnect2.c]
+     in ssh protocol v2 use ignore messages for padding (instead of
+     trailing \0).
+   - markus@cvs.openbsd.org 2001/02/28 12:55:07
+     [channels.c]
+     unify debug messages
+   - deraadt@cvs.openbsd.org 2001/02/28 17:52:54
+     [misc.c]
+     for completeness, copy pw_gecos too
+   - markus@cvs.openbsd.org 2001/02/28 21:21:41
+     [sshd.c]
+     generate a fake session id, too
+   - markus@cvs.openbsd.org 2001/02/28 21:27:48
+     [channels.c packet.c packet.h serverloop.c]
+     use ignore message to simulate a SSH2_MSG_CHANNEL_DATA message
+     use random content in ignore messages.
+   - markus@cvs.openbsd.org 2001/02/28 21:31:32
+     [channels.c]
+     typo
+   - deraadt@cvs.openbsd.org 2001/03/01 02:11:25
+     [authfd.c]
+     split line so that p will have an easier time next time around
+   - deraadt@cvs.openbsd.org 2001/03/01 02:29:04
+     [ssh.c]
+     shorten usage by a line
+   - deraadt@cvs.openbsd.org 2001/03/01 02:45:10
+     [auth-rsa.c auth2.c deattack.c packet.c]
+     KNF
+   - deraadt@cvs.openbsd.org 2001/03/01 03:38:33
+     [cli.c cli.h rijndael.h ssh-keyscan.1]
+     copyright notices on all source files
+   - markus@cvs.openbsd.org 2001/03/01 22:46:37
+     [ssh.c]
+     don't truncate remote ssh-2 commands; from mkubita@securities.cz
+     use min, not max for logging, fixes overflow.
+   - deraadt@cvs.openbsd.org 2001/03/02 06:21:01
+     [sshd.8]
+     explain SIGHUP better
+   - deraadt@cvs.openbsd.org 2001/03/02 09:42:49
+     [sshd.8]
+     doc the dsa/rsa key pair files
+   - deraadt@cvs.openbsd.org 2001/03/02 18:54:31
+     [atomicio.c atomicio.h auth-chall.c auth.c auth2-chall.c crc32.h
+      scp.c serverloop.c session.c sftp-server.8 sftp.1 ssh-add.1 ssh-add.c
+      ssh-agent.1 ssh-agent.c ssh-keygen.1 ssh.1 sshd.8]
+     make copyright lines the same format
+   - deraadt@cvs.openbsd.org 2001/03/03 06:53:12
+     [ssh-keyscan.c]
+     standard theo sweep
+   - millert@cvs.openbsd.org 2001/03/03 21:19:41
+     [ssh-keyscan.c]
+     Dynamically allocate read_wait and its copies.  Since maxfd is
+     based on resource limits it is often (usually?) larger than FD_SETSIZE.
+   - millert@cvs.openbsd.org 2001/03/03 21:40:30
+     [sftp-server.c]
+     Dynamically allocate fd_set; deraadt@ OK
+   - millert@cvs.openbsd.org 2001/03/03 21:41:07
+     [packet.c]
+     Dynamically allocate fd_set; deraadt@ OK
+   - deraadt@cvs.openbsd.org 2001/03/03 22:07:50
+     [sftp-server.c]
+     KNF
+   - markus@cvs.openbsd.org 2001/03/03 23:52:22
+     [sftp.c]
+     clean up arg processing. based on work by Christophe_Moret@hp.com
+   - markus@cvs.openbsd.org 2001/03/03 23:59:34
+     [log.c ssh.c]
+     log*.c -> log.c
+   - markus@cvs.openbsd.org 2001/03/04 00:03:59
+     [channels.c]
+     debug1->2
+   - stevesk@cvs.openbsd.org 2001/03/04 10:57:53
+     [ssh.c]
+     add -m to usage; ok markus@
+   - stevesk@cvs.openbsd.org 2001/03/04 11:04:41
+     [sshd.8]
+     small cleanup and clarify for PermitRootLogin; ok markus@
+   - stevesk@cvs.openbsd.org 2001/03/04 11:16:06
+     [servconf.c sshd.8]
+     kill obsolete RandomSeed; ok markus@ deraadt@
+   - stevesk@cvs.openbsd.org 2001/03/04 12:54:04
+     [sshd.8]
+     spelling
+   - millert@cvs.openbsd.org 2001/03/04 17:42:28
+     [authfd.c channels.c dh.c log.c readconf.c servconf.c sftp-int.c
+      ssh.c sshconnect.c sshd.c]
+     log functions should not be passed strings that end in newline as they
+     get passed on to syslog() and when logging to stderr, do_log() appends
+     its own newline.
+   - deraadt@cvs.openbsd.org 2001/03/04 18:21:28
+     [sshd.8]
+     list SSH2 ciphers
+ - (bal) Put HAVE_PW_CLASS_IN_PASSWD back into pwcopy()
+ - (bal) Fix up logging since it changed.  removed log-*.c
+ - (djm) Fix up LOG_AUTHPRIV for systems that have it
+ - (stevesk) OpenBSD sync:
+   - deraadt@cvs.openbsd.org 2001/03/05 08:37:27
+     [ssh-keyscan.c]
+     skip inlining, why bother
+ - (stevesk) sftp.c: handle __progname
+
+20010304
+ - (bal) Remove make-ssh-known-hosts.1 since it's no longer valid.
+ - (bal) Updated contrib/README to remove 'make-ssh-known-hosts' and
+   give Mark Roth credit for mdoc2man.pl
+
+20010303
+ - (djm) Remove make-ssh-known-hosts.pl, ssh-keyscan is better.
+ - (djm) Document PAM ChallengeResponseAuthentication in sshd.8
+ - (djm) Disable and comment ChallengeResponseAuthentication in sshd_config
+ - (djm) Allow PRNGd entropy collection from localhost TCP socket. Replace
+   "--with-egd-pool" configure option with "--with-prngd-socket" and
+   "--with-prngd-port" options. Debugged and improved by Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+
+20010301
+ - (djm) Properly add -lcrypt if needed.
+ - (djm) Force standard PAM conversation function in a few more places.
+   Patch from Redhat 2.5.1p1-2 RPM, probably Nalin Dahyabhai
+   <nalin@redhat.com>
+ - (djm) Cygwin needs pw->pw_gecos copied too. Patch from Corinna Vinschen
+   <vinschen@redhat.com>
+ - (djm) Released 2.5.1p2
+
+20010228
+ - (djm) Detect endianness in configure and use it in rijndael.c. Fixes
+   "Bad packet length" bugs.
+ - (djm) Fully revert PAM session patch (again). All PAM session init is
+   now done before the final fork().
+ - (djm) EGD detection patch from Tim Rice <tim@multitalents.net>
+ - (djm) Remove /tmp from EGD socket search list
+
+20010227
+ - (bal) Applied shutdown() patch for sftp.c by  Corinna Vinschen
+   <vinschen@redhat.com>
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/02/23 15:37:45
+     [session.c]
+     handle SSH_PROTOFLAG_SCREEN_NUMBER for buggy clients
+ - (bal) sshd.init support for all Redhat release.  Patch by Jim Knoble
+   <jmknoble@jmknoble.cx>
+ - (djm) Fix up POSIX saved uid support. Report from Mark Miller
+   <markm@swoon.net>
+ - (djm) Search for -lcrypt on FreeBSD too
+ - (djm) fatal() on OpenSSL version mismatch
+ - (djm) Move PAM init to after fork for non-Solaris derived PAMs
+ - (djm) Warning fix on entropy.c saved uid stuff. Patch from Mark Miller
+   <markm@swoon.net>
+ - (djm) Fix PAM fix
+ - (djm) Remove 'noreplace' flag from sshd_config in RPM spec files. This
+   change is being made as 2.5.x configfiles are not back-compatible with
+   2.3.x.
+ - (djm) Avoid warnings for missing broken IP_TOS. Patch from Mark Miller
+   <markm@swoon.net>
+ - (djm) Open Server 5 doesn't need BROKEN_SAVED_UIDS. Patch from Tim Rice
+   <tim@multitalents.net>
+ - (djm) Avoid multiple definition of _PATH_LS. Patch from Tim Rice
+   <tim@multitalents.net>
+
+20010226
+ - (bal) Fixed bsd-snprinf.c so it now honors 'BROKEN_SNPRINTF' again.
+ - (djm) Some systems (SCO3, NeXT) have weird saved uid semantics.
+   Based on patch from Tim Rice <tim@multitalents.net>
+
+20010225
+ - (djm) Use %{_libexecdir} rather than hardcoded path in RPM specfile
+   Patch from Adrian Ho <lexfiend@usa.net>
+ - (bal) Replace 'unsigned long long' to 'u_int64_t' since not every
+   platform defines u_int64_t as being that.
+
+20010224
+ - (bal) Missed part of the UNIX sockets patch.  Patch by Corinna
+   Vinschen <vinschen@redhat.com>
+ - (bal) Reorder where 'strftime' is detected to resolve linking
+   issues on SCO.  Patch by Tim Rice <tim@multitalents.net>
+
+20010224
+ - (bal) pam_stack fix to correctly detect between RH7 and older RHs.
+   Patch by Pekka Savola <pekkas@netcore.fi>
+ - (bal) Renamed sigaction.[ch] to sigact.[ch].  Causes problems with
+   some platforms.
+ - (bal) Generalize lack of UNIX sockets since this also effects Cray
+   not just Cygwin.  Based on patch by Wendy Palm <wendyp@cray.com>
+
+20010223
+ - (bal) Fix --define rh7 in openssh.spec file.  Patch by Steve Tell
+   <tell@telltronics.org>
+ - (bal) Patch to force OpenSSH rpm to require the same version of OpenSSL
+   that it was compiled against.  Patch by Pekka Savola <pekkas@netcore.fi>
+ - (bal) Double -I for OpenSSL on SCO.  Patch by Tim Rice
+   <tim@multitalents.net>
+
+20010222
+ - (bal) Corrected SCO luid patch by svaughan <svaughan@asterion.com>
+ - (bal) Added mdoc2man.pl from Mark Roth <roth@feep.net>
+ - (bal) Removed reference to liblogin from contrib/README.  It was
+   integrated into OpenSSH a long while ago.
+ - (stevesk) remove erroneous #ifdef sgi code.
+   Michael Stone <mstone@cs.loyola.edu>
+
+20010221
+ - (bal) Removed -L/usr/ucblib -R/usr/ucblib for Solaris platform.
+ - (bal) Fixed OpenSSL rework to use $saved_*.  Patch by Tim Rice
+   <tim@multitalents.net>
+ - (bal) Reverted out of 2001/02/15 patch by djm below because it
+   breaks Solaris.
+       - (djm) Move PAM session setup back to before setuid to user.
+         fixes problems on Solaris-drived PAMs.
+ - (stevesk) session.c: back out to where we were before:
+    - (djm) Move PAM session initialisation until after fork in sshd. Patch
+      from Nalin Dahyabhai <nalin@redhat.com>
+
+20010220
+ - (bal) Fix mixed up params to memmove() from Jan 5th in setenv.c and
+   getcwd.c.
+ - (bal) OpenBSD CVS Sync:
+   - deraadt@cvs.openbsd.org 2001/02/19 23:09:05
+     [sshd.c]
+     clarify message to make it not mention "ident"
+
+20010219
+ - (bal) Markus' blessing to rename login.[ch] -> sshlogin.[ch] and
+   pty.[ch] -> sshpty.[ch]
+ - (djm) Rework search for OpenSSL location. Skip directories which don't
+   exist, don't add -L$ssldir/lib if it doesn't exist. Should help SCO
+   with its limit of 6 -L options.
+ - OpenBSD CVS Sync:
+   - reinhard@cvs.openbsd.org        2001/02/17 08:24:40
+     [sftp.1]
+     typo
+   - deraadt@cvs.openbsd.org 2001/02/17 16:28:58
+     [ssh.c]
+     cleanup -V output; noted by millert
+   - deraadt@cvs.openbsd.org 2001/02/17 16:48:48
+     [sshd.8]
+     it's the OpenSSH one
+   - markus@cvs.openbsd.org  2001/02/18 11:33:54
+     [dispatch.c]
+     typo, SSH2_MSG_KEXINIT, from aspa@kronodoc.fi
+   - markus@cvs.openbsd.org  2001/02/19 02:53:32
+     [compat.c compat.h serverloop.c]
+     ssh-1.2.{18-22} has broken handling of ignore messages; report from
+     itojun@
+   - markus@cvs.openbsd.org  2001/02/19 03:35:23
+     [version.h]
+     OpenSSH_2.5.1 adds bug compat with 1.2.{18-22}
+   - deraadt@cvs.openbsd.org 2001/02/19 03:36:25
+     [scp.c]
+     np is changed by recursion; vinschen@redhat.com
+ - Update versions in RPM spec files
+ - Release 2.5.1p1
+
+20010218
+ - (bal) Patch for fix FCHMOD reference in ftp-client.c by Tim Rice
+   <tim@multitalents.net>
+ - (Bal) Patch for lack of RA_RESTART in misc.c for mysignal by
+   stevesk
+ - (djm) Fix my breaking of cygwin builds, Patch from Corinna Vinschen
+   <vinschen@redhat.com> and myself.
+ - (djm) Close listen_sock on bind() failures. Patch from Arkadiusz
+   Miskiewicz <misiek@pld.ORG.PL>
+ - (djm) Robustify EGD/PRNGd code in face of socket closures. Patch from
+   Todd C. Miller <Todd.Miller@courtesan.com>
+ - (djm) Use ttyname() to determine name of tty returned by openpty()
+   rather then risking overflow. Patch from Marek Michalkiewicz
+   <marekm@amelek.gda.pl>
+ - (djm) Swapped tests for no_libsocket and no_libnsl in configure.in.
+   Patch from Marek Michalkiewicz <marekm@amelek.gda.pl>
+ - (djm) Doc fixes from Pekka Savola <pekkas@netcore.fi>
+ - (djm) Use SA_INTERRUPT along SA_RESTART if present (equivalent for
+   SunOS)
+ - (djm) SCO needs librpc for libwrap. Patch from Tim Rice
+   <tim@multitalents.net>
+ - (stevesk) misc.c: cpp rework of SA_(INTERRUPT|RESTART) handling.
+ - (stevesk) scp.c: use mysignal() for updateprogressmeter() handler.
+ - (djm) SA_INTERRUPT is the converse of SA_RESTART, apply it only for
+   SIGALRM.
+ - (djm) Move entropy.c over to mysignal()
+ - (djm) SunOS 4.x also needs to define HAVE_BOGUS_SYS_QUEUE_H as it has
+   a <sys/queue.h> that lacks the TAILQ_* macros. Patch from Todd C.
+   Miller <Todd.Miller@courtesan.com>
+ - (djm) Update RPM spec files for 2.5.0p1
+ - (djm) Merge BSD_AUTH support from Markus Friedl and David J. MacKenzie
+   enable with --with-bsd-auth.
+ - (stevesk) entropy.c: typo; should be SIGPIPE
+
+20010217
+ - (bal) OpenBSD Sync:
+   - markus@cvs.openbsd.org 2001/02/16 13:38:18
+     [channel.c]
+     remove debug
+   - markus@cvs.openbsd.org 2001/02/16 14:03:43
+     [session.c]
+     proper payload-length check for x11 w/o screen-number
+
+20010216
+ - (bal) added '--with-prce'  to allow overriding of system regex when
+   required (tested by David Dulek <ddulek@fastenal.com>)
+ - (bal) Added DG/UX case and set that they have a broken IPTOS.
+ - (djm) Mini-configure reorder patch from Tim Rice <tim@multitalents.net>
+   Fixes linking on SCO.
+ - (djm) Make gnome-ssh-askpass handle multi-line prompts. Patch from
+   Nalin Dahyabhai <nalin@redhat.com>
+ - (djm) BSD license for gnome-ssh-askpass (was X11)
+ - (djm) KNF on gnome-ssh-askpass
+ - (djm) USE_PIPES for a few more sysv platforms
+ - (djm) Cleanup configure.in a little
+ - (djm) Ask users to check config.log when we can't find necessary libs
+ - (djm) Set "login ID" on systems with setluid. Only enabled for SCO
+   OpenServer for now. Based on patch from svaughan <svaughan@asterion.com>
+ - (djm) OpenBSD CVS:
+   - markus@cvs.openbsd.org  2001/02/15 16:19:59
+     [channels.c channels.h serverloop.c sshconnect.c sshconnect.h]
+     [sshconnect1.c sshconnect2.c]
+     genericize password padding function for SSH1 and SSH2.
+     add stylized echo to 2, too.
+ - (djm) Add roundup() macro to defines.h
+ - (stevesk) set SA_RESTART flag in mysignal() for SIGCHLD;
+   needed on Unixware 2.x.
+
+20010215
+ - (djm) Move PAM session setup back to before setuid to user. Fixes
+   problems on Solaris-derived PAMs.
+ - (djm) Clean up PAM namespace. Suggested by Darren Moffat
+   <Darren.Moffat@eng.sun.com>
+ - (bal) Sync w/ OpenSSH for new release
+   - markus@cvs.openbsd.org 2001/02/12 12:45:06
+     [sshconnect1.c]
+     fix xmalloc(0), ok dugsong@
+   - markus@cvs.openbsd.org 2001/02/11 12:59:25
+     [Makefile.in sshd.8 sshconnect2.c readconf.h readconf.c packet.c
+      sshd.c ssh.c ssh.1 servconf.h servconf.c myproposal.h kex.h kex.c]
+     1) clean up the MAC support for SSH-2
+     2) allow you to specify the MAC with 'ssh -m'
+     3) or the 'MACs' keyword in ssh(d)_config
+     4) add hmac-{md5,sha1}-96
+             ok stevesk@, provos@
+   - markus@cvs.openbsd.org 2001/02/12 16:16:23
+     [auth-passwd.c auth.c auth.h auth1.c auth2.c servconf.c servconf.h
+      ssh-keygen.c sshd.8]
+     PermitRootLogin={yes,without-password,forced-commands-only,no}
+     (before this change, root could login even if PermitRootLogin==no)
+   - deraadt@cvs.openbsd.org 2001/02/12 22:56:09
+     [clientloop.c packet.c ssh-keyscan.c]
+     deal with EAGAIN/EINTR selects which were skipped
+   - markus@cvs.openssh.org 2001/02/13 22:49:40
+     [auth1.c auth2.c]
+     setproctitle(user) only if getpwnam succeeds
+   - markus@cvs.openbsd.org 2001/02/12 23:26:20
+     [sshd.c]
+     missing memset; from solar@openwall.com
+   - stevesk@cvs.openbsd.org 2001/02/12 20:53:33
+     [sftp-int.c]
+     lumask now works with 1 numeric arg; ok markus@, djm@
+   - djm@cvs.openbsd.org 2001/02/14 9:46:03
+     [sftp-client.c sftp-int.c sftp.1]
+     Fix and document 'preserve modes & times' option ('-p' flag in sftp);
+     ok markus@
+ - (bal) replaced PATH_MAX in sftp-int.c w/ MAXPATHLEN.
+ - (djm) Move to Jim's 1.2.0 X11 askpass program
+ - (stevesk) OpenBSD sync:
+   - deraadt@cvs.openbsd.org 2001/02/15 01:38:04
+     [serverloop.c]
+     indent
+
+20010214
+ - (djm) Don't try to close PAM session or delete credentials if the
+   session has not been open or credentials not set. Based on patch from
+   Andrew Bartlett <abartlet@pcug.org.au>
+ - (djm) Move PAM session initialisation until after fork in sshd. Patch
+   from Nalin Dahyabhai <nalin@redhat.com>
+ - (bal) Missing function prototype in bsd-snprintf.c patch by
+   Mark Miller <markm@swoon.net>
+ - (djm) Split out and improve OSF SIA auth code. Patch from Chris Adams
+   <cmadams@hiwaay.net> with a little modification and KNF.
+ - (stevesk) fix for SIA patch, misplaced session_setup_sia()
+
+20010213
+ - (djm) Only test -S potential EGD sockets if they exist and are readable.
+ - (bal) Cleaned out bsd-snprintf.c.  VARARGS have been banished and
+   I did a base KNF over the whe whole file to make it more acceptable.
+   (backed out of original patch and removed it from ChangeLog)
+ - (bal) Use chown() if fchown() does not exist in ftp-server.c patch by
+   Tim Rice <tim@multitalents.net>
+ - (stevesk) auth1.c: fix PAM passwordless check.
+
+20010212
+ - (djm) Update Redhat specfile to allow --define "skip_x11_askpass 1",
+   --define "skip_gnome_askpass 1", --define "rh7 1" and make the
+   implicit rpm-3.0.5 dependancy explicit. Patch and suggestions from
+   Pekka Savola <pekkas@netcore.fi>
+ - (djm) Clean up PCRE text in INSTALL
+ - (djm) Fix OSF SIA auth NULL pointer deref. Report from Mike Battersby
+   <mib@unimelb.edu.au>
+ - (bal) NCR SVR4 compatiblity provide by Don Bragg <thewizarddon@yahoo.com>
+ - (stevesk) session.c: remove debugging code.
+
+20010211
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/02/07 22:35:46
+     [auth1.c auth2.c sshd.c]
+     move k_setpag() to a central place; ok dugsong@
+   - markus@cvs.openbsd.org 2001/02/10 12:52:02
+     [auth2.c]
+     offer passwd before s/key
+   - markus@cvs.openbsd.org 2001/02/8 22:37:10
+     [canohost.c]
+     remove last call to sprintf; ok deraadt@
+   - markus@cvs.openbsd.org 2001/02/10 1:33:32
+     [canohost.c]
+     add debug message, since sshd blocks here if DNS is not available
+   - markus@cvs.openbsd.org 2001/02/10 12:44:02
+     [cli.c]
+     don't call vis() for \r
+   - danh@cvs.openbsd.org 2001/02/10 0:12:43
+     [scp.c]
+     revert a small change to allow -r option to work again; ok deraadt@
+   - danh@cvs.openbsd.org 2001/02/10 15:14:11
+     [scp.c]
+     fix memory leak; ok markus@
+   - djm@cvs.openbsd.org 2001/02/10 0:45:52
+     [scp.1]
+     Mention that you can quote pathnames with spaces in them
+   - markus@cvs.openbsd.org 2001/02/10 1:46:28
+     [ssh.c]
+     remove mapping of argv[0] -> hostname
+   - markus@cvs.openbsd.org 2001/02/06 22:26:17
+     [sshconnect2.c]
+     do not ask for passphrase in batch mode; report from ejb@ql.org
+   - itojun@cvs.opebsd.org 2001/02/08 10:47:05
+     [sshconnect.c sshconnect1.c sshconnect2.c]
+     %.30s is too short for IPv6 numeric address.  use %.128s for now.
+     markus ok
+   - markus@cvs.openbsd.org 2001/02/09 12:28:35
+     [sshconnect2.c]
+     do not free twice, thanks to /etc/malloc.conf
+   - markus@cvs.openbsd.org 2001/02/09 17:10:53
+     [sshconnect2.c]
+     partial success: debug->log; "Permission denied" if no more auth methods
+   - markus@cvs.openbsd.org 2001/02/10 12:09:21
+     [sshconnect2.c]
+     remove some lines
+   - markus@cvs.openbsd.org 2001/02/09 13:38:07
+     [auth-options.c]
+     reset options if no option is given; from han.holl@prismant.nl
+   - markus@cvs.openbsd.org 2001/02/08 21:58:28
+     [channels.c]
+     nuke sprintf, ok deraadt@
+   - markus@cvs.openbsd.org 2001/02/08 21:58:28
+     [channels.c]
+     nuke sprintf, ok deraadt@
+   - markus@cvs.openbsd.org 2001/02/06 22:43:02
+     [clientloop.h]
+     remove confusing callback code
+   - deraadt@cvs.openbsd.org 2001/02/08 14:39:36
+     [readconf.c]
+     snprintf
+   - itojun@cvs.openbsd.org 2001/02/08 19:30:52
+     sync with netbsd tree changes.
+     - more strict prototypes, include necessary headers
+     - use paths.h/pathnames.h decls
+     - size_t typecase to int -> u_long
+   - itojun@cvs.openbsd.org 2001/02/07 18:04:50
+     [ssh-keyscan.c]
+     fix size_t -> int cast (use u_long).  markus ok
+   - markus@cvs.openbsd.org 2001/02/07 22:43:16
+     [ssh-keyscan.c]
+     s/getline/Linebuf_getline/; from roumen.petrov@skalasoft.com
+   - itojun@cvs.openbsd.org 2001/02/09 9:04:59
+     [ssh-keyscan.c]
+     do not assume malloc() returns zero-filled region.  found by
+     malloc.conf=AJ.
+   - markus@cvs.openbsd.org 2001/02/08 22:35:30
+     [sshconnect.c]
+     don't connect if batch_mode is true and stricthostkeychecking set to
+    'ask'
+   - djm@cvs.openbsd.org 2001/02/04 21:26:07
+     [sshd_config]
+     type: ok markus@
+   - deraadt@cvs.openbsd.org 2001/02/06 22:07:50
+     [sshd_config]
+     enable sftp-server by default
+   - deraadt 2001/02/07 8:57:26
+     [xmalloc.c]
+     deal with new ANSI malloc stuff
+   - markus@cvs.openbsd.org 2001/02/07 16:46:08
+     [xmalloc.c]
+     typo in fatal()
+   - itojun@cvs.openbsd.org 2001/02/07 18:04:50
+     [xmalloc.c]
+     fix size_t -> int cast (use u_long).  markus ok
+   - 1.47 Thu Feb 8 23:11:42 GMT 2001 by dugsong
+     [serverloop.c sshconnect1.c]
+     mitigate SSH1 traffic analysis - from Solar Designer
+     <solar@openwall.com>, ok provos@
+ - (bal) fixed sftp-client.c.  Return 'status' instead of '0'
+   (from the OpenBSD tree)
+ - (bal) Synced ssh.1, ssh-add.1 and sshd.8 w/ OpenBSD
+ - (bal) sftp-sever.c  '%8lld' to '%8llu' (OpenBSD Sync)
+ - (bal) uuencode.c resync w/ OpenBSD tree, plus whitespace.
+ - (bal) A bit more whitespace cleanup
+ - (djm) Set PAM_RHOST earlier, patch from Andrew Bartlett
+   <abartlet@pcug.org.au>
+ - (stevesk) misc.c: ssh.h not needed.
+ - (stevesk) compat.c: more friendly cpp error
+ - (stevesk) OpenBSD sync:
+   - stevesk@cvs.openbsd.org 2001/02/11 06:15:57
+     [LICENSE]
+     typos and small cleanup; ok deraadt@
+
+20010210
+ - (djm) Sync sftp and scp stuff from OpenBSD:
+   - djm@cvs.openbsd.org     2001/02/07 03:55:13
+     [sftp-client.c]
+     Don't free handles before we are done with them. Based on work from
+     Corinna Vinschen <vinschen@redhat.com>. ok markus@
+   - djm@cvs.openbsd.org     2001/02/06 22:32:53
+     [sftp.1]
+     Punctuation fix from Pekka Savola <pekkas@netcore.fi>
+   - deraadt@cvs.openbsd.org 2001/02/07 04:07:29
+     [sftp.1]
+     pretty up significantly
+   - itojun@cvs.openbsd.org  2001/02/07 06:49:42
+     [sftp.1]
+     .Bl-.El mismatch.  markus ok
+   - djm@cvs.openbsd.org     2001/02/07 06:12:30
+     [sftp-int.c]
+     Check that target is a directory before doing ls; ok markus@
+   - itojun@cvs.openbsd.org  2001/02/07 11:01:18
+     [scp.c sftp-client.c sftp-server.c]
+     unsigned long long -> %llu, not %qu.  markus ok
+   - stevesk@cvs.openbsd.org 2001/02/07 11:10:39
+     [sftp.1 sftp-int.c]
+     more man page cleanup and sync of help text with man page; ok markus@
+   - markus@cvs.openbsd.org  2001/02/07 14:58:34
+     [sftp-client.c]
+     older servers reply with SSH2_FXP_NAME + count==0 instead of EOF
+   - djm@cvs.openbsd.org     2001/02/07 15:27:19
+     [sftp.c]
+     Don't forward agent and X11 in sftp. Suggestion from Roumen Petrov
+     <roumen.petrov@skalasoft.com>
+   - stevesk@cvs.openbsd.org 2001/02/07 15:36:04
+     [sftp-int.c]
+     portable; ok markus@
+   - stevesk@cvs.openbsd.org 2001/02/07 15:55:47
+     [sftp-int.c]
+     lowercase cmds[].c also; ok markus@
+   - markus@cvs.openbsd.org  2001/02/07 17:04:52
+     [pathnames.h sftp.c]
+     allow sftp over ssh protocol 1; ok djm@
+   - deraadt@cvs.openbsd.org 2001/02/08 07:38:55
+     [scp.c]
+     memory leak fix, and snprintf throughout
+   - deraadt@cvs.openbsd.org 2001/02/08 08:02:02
+     [sftp-int.c]
+     plug a memory leak
+   - stevesk@cvs.openbsd.org 2001/02/08 10:11:23
+     [session.c sftp-client.c]
+     %i -> %d
+   - stevesk@cvs.openbsd.org 2001/02/08 10:57:59
+     [sftp-int.c]
+     typo
+   - stevesk@cvs.openbsd.org 2001/02/08 15:28:07
+     [sftp-int.c pathnames.h]
+     _PATH_LS; ok markus@
+   - djm@cvs.openbsd.org     2001/02/09 04:46:25
+     [sftp-int.c]
+     Check for NULL attribs for chown, chmod & chgrp operations, only send
+     relevant attribs back to server; ok markus@
+   - djm@cvs.openbsd.org     2001/02/06 15:05:25
+     [sftp.c]
+     Use getopt to process commandline arguments
+   - djm@cvs.openbsd.org     2001/02/06 15:06:21
+     [sftp.c ]
+     Wait for ssh subprocess at exit
+   - djm@cvs.openbsd.org     2001/02/06 15:18:16
+     [sftp-int.c]
+     stat target for remote chdir before doing chdir
+   - djm@cvs.openbsd.org     2001/02/06 15:32:54
+     [sftp.1]
+     Punctuation fix from Pekka Savola <pekkas@netcore.fi>
+   - provos@cvs.openbsd.org  2001/02/05 22:22:02
+     [sftp-int.c]
+     cleanup get_pathname, fix pwd after failed cd. okay djm@
+ - (djm) Update makefile.in for _PATH_SFTP_SERVER
+ - (bal) sftp-client.c replace NULL w/ 0 in do_ls() (pending in OpenBSD tree)
+
+20010209
+ - (bal) patch to vis.c to deal with HAVE_VIS right by Robert Mooney
+   <rjmooney@mediaone.net>
+ - (bal) .c.o rule in openbsd-compat/Makefile.in did not make it to the
+   main tree while porting forward.  Pointed out by Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - (bal) double entry in configure.in.  Pointed out by Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - (stevesk) OpenBSD sync:
+   - markus@cvs.openbsd.org  2001/02/08 11:20:01
+     [auth2.c]
+     strict checking
+   - markus@cvs.openbsd.org  2001/02/08 11:15:22
+     [version.h]
+     update to 2.3.2
+   - markus@cvs.openbsd.org  2001/02/08 11:12:30
+     [auth2.c]
+     fix typo
+ - (djm) Update spec files
+ - (bal) OpenBSD sync:
+   - deraadt@cvs.openbsd.org 2001/02/08 14:38:54
+     [scp.c]
+     memory leak fix, and snprintf throughout
+   - markus@cvs.openbsd.org 2001/02/06 22:43:02
+     [clientloop.c]
+     remove confusing callback code
+ - (djm) Add CVS Id's to files that we have missed
+ - (bal) OpenBSD Sync (more):
+   - itojun@cvs.openbsd.org 2001/02/08 19:30:52
+     sync with netbsd tree changes.
+     - more strict prototypes, include necessary headers
+     - use paths.h/pathnames.h decls
+     - size_t typecase to int -> u_long
+   - markus@cvs.openbsd.org 2001/02/06 22:07:42
+     [ssh.c]
+     fatal() if subsystem fails
+   - markus@cvs.openbsd.org 2001/02/06 22:43:02
+     [ssh.c]
+     remove confusing callback code
+   - jakob@cvs.openbsd.org 2001/02/06 23:03:24
+     [ssh.c]
+     add -1 option (force protocol version 1). ok markus@
+   - jakob@cvs.openbsd.org 2001/02/06 23:06:21
+     [ssh.c]
+     reorder -{1,2,4,6} options. ok markus@
+ - (bal) Missing 'const' in readpass.h
+ - (bal) OpenBSD Sync (so at least the thing compiles for 2.3.2 =)
+   - djm@cvs.openbsd.org 2001/02/06 23:30:28
+     [sftp-client.c]
+     replace arc4random with counter for request ids; ok markus@
+ - (djm) Define _PATH_TTY for systems that don't. Report from Lutz
+   Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+
+20010208
+ - (djm) Don't delete external askpass program in make uninstall target.
+   Report and fix from Roumen Petrov <roumen.petrov@skalasoft.com>
+ - (djm) Fix linking of sftp, don't need arc4random any more.
+ - (djm) Try to use shell that supports "test -S" for EGD socket search.
+   Based on patch from Tim Rice <tim@multitalents.net>
+
+20010207
+ - (bal) Save the whole path to AR in configure.  Some Solaris 2.7 installs
+   seem lose track of it while in openbsd-compat/  (two confirmed reports)
+ - (djm) Much KNF on PAM code
+ - (djm) Revise auth-pam.c conversation function to be a little more
+   readable.
+ - (djm) Revise kbd-int PAM conversation function to fold all text messages
+   to before first prompt. Fixes hangs if last pam_message did not require
+   a reply.
+ - (djm) Fix password changing when using PAM kbd-int authentication
+
+20010205
+ - (bal) Disable groupaccess by setting NGROUPS_MAX to 0 for platforms
+   that don't have NGROUPS_MAX.
+ - (bal) AIX patch for auth1.c by William L. Jones <jones@hpc.utexas.edu>
+ - (stevesk) OpenBSD sync:
+   - stevesk@cvs.openbsd.org 2001/02/04 08:32:27
+     [many files; did this manually to our top-level source dir]
+     unexpand and remove end-of-line whitespace; ok markus@
+   - stevesk@cvs.openbsd.org 2001/02/04 15:21:19
+     [sftp-server.c]
+     SSH2_FILEXFER_ATTR_UIDGID support; ok markus@
+   - deraadt@cvs.openbsd.org 2001/02/04 17:02:32
+     [sftp-int.c]
+     ? == help
+   - deraadt@cvs.openbsd.org 2001/02/04 16:47:46
+     [sftp-int.c]
+     sort commands, so that abbreviations work as expected
+   - stevesk@cvs.openbsd.org 2001/02/04 15:17:52
+     [sftp-int.c]
+     debugging sftp: precedence and missing break.  chmod, chown, chgrp
+     seem to be working now.
+   - markus@cvs.openbsd.org 2001/02/04 14:41:21
+     [sftp-int.c]
+     use base 8 for umask/chmod
+   - markus@cvs.openbsd.org 2001/02/04 11:11:54
+     [sftp-int.c]
+     fix LCD
+   - markus@cvs.openbsd.org  2001/02/04 08:10:44
+     [ssh.1]
+     typo; dpo@club-internet.fr
+   - stevesk@cvs.openbsd.org 2001/02/04 06:30:12
+     [auth2.c authfd.c packet.c]
+     remove duplicate #include's; ok markus@
+   - deraadt@cvs.openbsd.org 2001/02/04 16:56:23
+     [scp.c sshd.c]
+     alpha happiness
+   - stevesk@cvs.openbsd.org 2001/02/04 15:12:17
+     [sshd.c]
+     precedence; ok markus@
+   - deraadt@cvs.openbsd.org 2001/02/04 08:14:15
+     [ssh.c sshd.c]
+     make the alpha happy
+   - markus@cvs.openbsd.org  2001/01/31 13:37:24
+     [channels.c channels.h serverloop.c ssh.c]
+     do not disconnect if local port forwarding fails, e.g. if port is
+     already in use
+   - markus@cvs.openbsd.org  2001/02/01 14:58:09
+     [channels.c]
+     use ipaddr in channel messages, ietf-secsh wants this
+   - markus@cvs.openbsd.org  2001/01/31 12:26:20
+     [channels.c]
+     ssh.com-2.0.1x does not send additional info in CHANNEL_OPEN_FAILURE
+     messages; bug report from edmundo@rano.org
+   - markus@cvs.openbsd.org  2001/01/31 13:48:09
+     [sshconnect2.c]
+     unused
+   - deraadt@cvs.openbsd.org 2001/02/04 08:23:08
+     [sftp-client.c sftp-server.c]
+     make gcc on the alpha even happier
+
+20010204
+ - (bal) I think this is the last of the bsd-*.h that don't belong.
+ - (bal) Minor Makefile fix
+ - (bal) openbsd-compat/Makefile minor fix.  Ensure dependancies are done
+   right.
+ - (bal) Changed order of LIB="" in -with-skey due to library resolving.
+ - (bal) next-posix.h changed to bsd-nextstep.h
+ - (djm) OpenBSD CVS sync:
+   - markus@cvs.openbsd.org  2001/02/03 03:08:38
+     [auth-options.c auth-rh-rsa.c auth-rhosts.c auth.c canohost.c]
+     [canohost.h servconf.c servconf.h session.c sshconnect1.c sshd.8]
+     [sshd_config]
+     make ReverseMappingCheck optional in sshd_config; ok djm@,dugsong@
+   - markus@cvs.openbsd.org  2001/02/03 03:19:51
+     [ssh.1 sshd.8 sshd_config]
+     Skey is now called ChallengeResponse
+   - markus@cvs.openbsd.org  2001/02/03 03:43:09
+     [sshd.8]
+     use no-pty option in .ssh/authorized_keys* if you need a 8-bit clean
+     channel. note from Erik.Anggard@cygate.se (pr/1659)
+   - stevesk@cvs.openbsd.org 2001/02/03 10:03:06
+     [ssh.1]
+     typos; ok markus@
+   - djm@cvs.openbsd.org     2001/02/04 04:11:56
+     [scp.1 sftp-server.c ssh.1 sshd.8 sftp-client.c sftp-client.h]
+     [sftp-common.c sftp-common.h sftp-int.c sftp-int.h sftp.1 sftp.c]
+     Basic interactive sftp client; ok theo@
+ - (djm) Update RPM specs for new sftp binary
+ - (djm) Update several bits for new optional reverse lookup stuff. I
+   think I got them all.
+ - (djm) Makefile.in fixes
+ - (stevesk) add mysignal() wrapper and use it for the protocol 2
+   SIGCHLD handler.
+ - (djm) Use setvbuf() instead of setlinebuf(). Suggest from stevesk@
+
+20010203
+ - (bal) Cygwin clean up by Corinna Vinschen <vinschen@redhat.com>
+ - (bal) renamed queue.h to fake-queue.h (even if it's an OpenBSD
+   based file) to ensure #include space does not get confused.
+ - (bal) Minor Makefile.in tweak.  dirname may not exist on some
+   platforms so builds fail.  (NeXT being a well known one)
+
+20010202
+ - (bal) Makefile fix where sourcedir != builddir by Corinna Vinschen
+   <vinschen@redhat.com>
+ - (bal) Makefile fix to use $(MAKE) instead of 'make'  for platforms
+   that use 'gmake'.   Patch by Tim Rice <tim@multitalents.net>
+
+20010201
+ - (bal) Minor fix to Makefile to stop rebuilding executables if no
+   changes have occured to any of the supporting code.  Patch by
+   Roumen Petrov <roumen.petrov@skalasoft.com>
+
+20010131
+ - (djm) OpenBSD CVS Sync:
+   - djm@cvs.openbsd.org     2001/01/30 15:48:53
+     [sshconnect.c]
+     Make warning message a little more consistent. ok markus@
+ - (djm) Fix autoconf logic for --with-lastlog=no Report and diagnosis from
+   Philipp Buehler <lists@fips.de> and Kevin Steves <stevesk@sweden.hp.com>
+   respectively.
+ - (djm) Don't log SSH2 PAM KbdInt responses to debug, they may contain
+   passwords.
+ - (bal) Reorder.  Move all bsd-*, fake-*, next-*, and cygwin* stuff to
+   openbsd-compat/.  And resolve all ./configure and Makefile.in issues
+   assocated.
+
+20010130
+ - (djm) OpenBSD CVS Sync:
+   - markus@cvs.openbsd.org  2001/01/29 09:55:37
+     [channels.c channels.h clientloop.c serverloop.c]
+     fix select overflow; ok deraadt@ and stevesk@
+   - markus@cvs.openbsd.org  2001/01/29 12:42:35
+     [canohost.c canohost.h channels.c clientloop.c]
+     add get_peer_ipaddr(socket), x11-fwd in ssh2 requires ipaddr, not DNS
+   - markus@cvs.openbsd.org  2001/01/29 12:47:32
+     [rsa.c rsa.h ssh-agent.c sshconnect1.c sshd.c]
+     handle rsa_private_decrypt failures; helps against the Bleichenbacher
+     pkcs#1 attack
+   - djm@cvs.openbsd.org     2001/01/29 05:36:11
+     [ssh.1 ssh.c]
+     Allow invocation of sybsystem by commandline (-s); ok markus@
+ - (stevesk) configure.in: remove duplicate PROG_LS
+
+20010129
+ - (stevesk) sftp-server.c: use %lld vs. %qd
+
+20010128
+ - (bal) Put USE_PIPES back into sco3.2v5
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/01/28 10:15:34
+     [dispatch.c]
+     re-keying is not supported; ok deraadt@
+   - markus@cvs.openbsd.org 2001/01/28 10:24:04
+     [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8]
+     cleanup AUTHORS sections
+   - markus@cvs.openbsd.org 2001/01/28 10:37:26
+     [sshd.c sshd.8]
+     remove -Q, no longer needed
+   - stevesk@cvs.openbsd.org 2001/01/28 20:36:16
+     [readconf.c ssh.1]
+     ``StrictHostKeyChecking ask'' documentation and small cleanup.
+     ok markus@
+   - stevesk@cvs.openbsd.org 2001/01/28 20:43:25
+     [sshd.8]
+     spelling.  ok markus@
+   - stevesk@cvs.openbsd.org 2001/01/28 20:53:21
+     [xmalloc.c]
+     use size_t for strlen() return.  ok markus@
+   - stevesk@cvs.openbsd.org 2001/01/28 22:27:05
+     [authfile.c]
+     spelling.  use sizeof vs. strlen().  ok markus@
+   - niklas@cvs.openbsd.org 2001/01/29 1:59:14
+     [atomicio.h canohost.h clientloop.h deattack.h dh.h dispatch.h
+      groupaccess.c groupaccess.h hmac.h hostfile.h includes.h kex.h
+      key.h log.h login.h match.h misc.h myproposal.h nchan.ms pathnames.h
+      radix.h readpass.h rijndael.h serverloop.h session.h sftp.h ssh-add.1
+      ssh-dss.h ssh-keygen.1 ssh-keyscan.1 ssh-rsa.h ssh1.h ssh_config
+      sshconnect.h sshd_config tildexpand.h uidswap.h uuencode.h]
+     $OpenBSD$
+  - (bal) Minor auth2.c resync.  Whitespace and moving of an #include.
+
+20010126
+ - (bal) SSH_PROGRAM vs _PATH_SSH_PROGRAM fix pointed out by Roumen
+   Petrov <roumen.petrov@skalasoft.com>
+ - (bal) OpenBSD Sync
+   - deraadt@cvs.openbsd.org 2001/01/25 8:06:33
+     [ssh-agent.c]
+     call _exit() in signal handler
+
+20010125
+ - (djm) Sync bsd-* support files:
+   - deraadt@cvs.openbsd.org 2000/01/26 03:43:20
+     [rresvport.c bindresvport.c]
+     new bindresvport() semantics that itojun, shin, jean-luc and i have
+     agreed on, which will be happy for the future. bindresvport_sa() for
+     sockaddr *, too.  docs later..
+   - deraadt@cvs.openbsd.org 2000/01/24 02:24:21
+     [bindresvport.c]
+     in bindresvport(), if sin is non-NULL, example sin->sin_family for
+     the actual family being processed
+ - (djm) Mention PRNGd in documentation, it is nicer than EGD
+ - (djm) Automatically search for "well-known" EGD/PRNGd sockets in autoconf
+ - (bal) AC_FUNC_STRFTIME added to autoconf
+ - (bal) OpenBSD Resync
+   - stevesk@cvs.openbsd.org 2001/01/24 21:03:50
+     [channels.c]
+     missing freeaddrinfo(); ok markus@
+
+20010124
+ - (bal) OpenBSD Resync
+   - markus@cvs.openbsd.org 2001/01/23 10:45:10
+     [ssh.h]
+     nuke comment
+ - (bal) no 64bit support patch from Tim Rice <tim@multitalents.net>
+ - (bal) #ifdef around S_IFSOCK if platform does not support it.
+   patch by Tim Rice <tim@multitalents.net>
+ - (bal) fake-regex.h cleanup based on Tim Rice's patch.
+ - (stevesk) sftp-server.c: fix chmod() mode mask
+
+20010123
+ - (bal) regexp.h typo in configure.in.  Should have been regex.h
+ - (bal) SSH_USER_DIR to _PATH_SSH_USER_DIR patch by stevesk@
+ - (bal) SSH_ASKPASS_DEFAULT to _PATH_SSH_ASKPASS_DEFAULT
+ - (bal) OpenBSD Resync
+   - markus@cvs.openbsd.org 2001/01/22 8:15:00
+     [auth-krb4.c sshconnect1.c]
+     only AFS needs radix.[ch]
+   - markus@cvs.openbsd.org 2001/01/22 8:32:53
+     [auth2.c]
+     no need to include; from mouring@etoh.eviladmin.org
+   - stevesk@cvs.openbsd.org 2001/01/22 16:55:21
+     [key.c]
+     free() -> xfree(); ok markus@
+   - stevesk@cvs.openbsd.org 2001/01/22 17:22:28
+     [sshconnect2.c sshd.c]
+     fix memory leaks in SSH2 key exchange; ok markus@
+   - markus@cvs.openbsd.org 2001/01/22 23:06:39
+     [auth1.c auth2.c readconf.c readconf.h servconf.c servconf.h
+      sshconnect1.c sshconnect2.c sshd.c]
+     rename skey -> challenge response.
+     auto-enable kbd-interactive for ssh2 if challenge-reponse is enabled.
+
+
+20010122
+ - (bal) OpenBSD Resync
+   - markus@cvs.openbsd.org 2001/01/19 12:45:26 GMT 2001 by markus
+     [servconf.c ssh.h sshd.c]
+     only auth-chall.c needs #ifdef SKEY
+   - markus@cvs.openbsd.org 2001/01/19 15:55:10 GMT 2001 by markus
+     [auth-krb4.c auth-options.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c
+      auth1.c auth2.c channels.c clientloop.c dh.c dispatch.c nchan.c
+      packet.c pathname.h readconf.c scp.c servconf.c serverloop.c
+      session.c ssh-add.c ssh-keygen.c ssh-keyscan.c ssh.c ssh.h
+      ssh1.h sshconnect1.c sshd.c ttymodes.c]
+     move ssh1 definitions to ssh1.h, pathnames to pathnames.h
+   - markus@cvs.openbsd.org 2001/01/19 16:48:14
+     [sshd.8]
+     fix typo; from stevesk@
+   - markus@cvs.openbsd.org 2001/01/19 16:50:58
+     [ssh-dss.c]
+     clear and free digest, make consistent with other code (use dlen); from
+     stevesk@
+   - markus@cvs.openbsd.org 2001/01/20 15:55:20 GMT 2001 by markus
+     [auth-options.c auth-options.h auth-rsa.c auth2.c]
+     pass the filename to auth_parse_options()
+   - markus@cvs.openbsd.org 2001/01/20 17:59:40 GMT 2001
+     [readconf.c]
+     fix SIGSEGV from -o ""; problem noted by jehsom@togetherweb.com
+   - stevesk@cvs.openbsd.org 2001/01/20 18:20:29
+     [sshconnect2.c]
+     dh_new_group() does not return NULL.  ok markus@
+   - markus@cvs.openbsd.org 2001/01/20 21:33:42
+     [ssh-add.c]
+     do not loop forever if askpass does not exist; from
+     andrew@pimlott.ne.mediaone.net
+   - djm@cvs.openbsd.org 2001/01/20 23:00:56
+     [servconf.c]
+     Check for NULL return from strdelim; ok markus
+   - djm@cvs.openbsd.org 2001/01/20 23:02:07
+     [readconf.c]
+     KNF; ok markus
+   - jakob@cvs.openbsd.org 2001/01/21 9:00:33
+     [ssh-keygen.1]
+     remove -R flag; ok markus@
+   - markus@cvs.openbsd.org 2001/01/21 19:05:40
+     [atomicio.c automicio.h auth-chall.c auth-krb4.c auth-options.c
+      auth-options.h auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c
+      auth.c auth.h auth1.c auth2-chall.c auth2.c authfd.c authfile.c
+      bufaux.c  bufaux.h buffer.c canahost.c canahost.h channels.c
+      cipher.c cli.c clientloop.c clientloop.h compat.c compress.c
+      deattack.c dh.c dispatch.c groupaccess.c hmac.c hostfile.c kex.c
+      key.c key.h log-client.c log-server.c log.c log.h login.c login.h
+      match.c misc.c misc.h nchan.c packet.c pty.c radix.h readconf.c
+      readpass.c readpass.h rsa.c scp.c servconf.c serverloop.c serverloop.h
+      session.c sftp-server.c ssh-add.c ssh-agent.c ssh-dss.c ssh-keygen.c
+      ssh-keyscan.c ssh-rsa.c ssh.c ssh.h sshconnect.c sshconnect.h
+      sshconnect1.c sshconnect2.c sshd.c tildexpand.c tildexpand.h
+      ttysmodes.c uidswap.c xmalloc.c]
+     split ssh.h and try to cleanup the #include mess. remove unnecessary
+     #includes.  rename util.[ch] -> misc.[ch]
+ - (bal) renamed 'PIDDIR' to '_PATH_SSH_PIDDIR' to match OpenBSD tree
+ - (bal) Moved #ifdef KRB4 in auth-krb4.c above the #include to resolve
+   conflict when compiling for non-kerb install
+ - (bal) removed the #ifdef SKEY in auth1.c to match Markus' changes
+   on 1/19.
+
+20010120
+ - (bal) OpenBSD Resync
+   - markus@cvs.openbsd.org 2001/01/19 12:45:26
+     [ssh-chall.c servconf.c servconf.h ssh.h sshd.c]
+     only auth-chall.c needs #ifdef SKEY
+ - (bal) Slight auth2-pam.c clean up.
+ - (bal) Includes a fake-regexp.h to be only used if regcomp() is found,
+   but no 'regexp.h' found (SCO OpenServer 3 lacks the header).
+
+20010119
+ - (djm) Update versions in RPM specfiles
+ - (bal) OpenBSD Resync
+   - markus@cvs.openbsd.org 2001/01/18 16:20:21
+     [log-client.c log-server.c log.c readconf.c servconf.c ssh.1 ssh.h
+      sshd.8 sshd.c]
+     log() is at pri=LOG_INFO, since LOG_NOTICE goes to /dev/console on many
+     systems
+   - markus@cvs.openbsd.org 2001/01/18 16:59:59
+     [auth-passwd.c auth.c auth.h auth1.c auth2.c serverloop.c session.c
+      session.h sshconnect1.c]
+     1) removes fake skey from sshd, since this will be much
+        harder with /usr/libexec/auth/login_XXX
+     2) share/unify code used in ssh-1 and ssh-2 authentication (server side)
+     3) make addition of BSD_AUTH and other challenge reponse methods
+        easier.
+   - markus@cvs.openbsd.org 2001/01/18 17:12:43
+     [auth-chall.c auth2-chall.c]
+     rename *-skey.c *-chall.c since the files are not skey specific
+ - (djm) Merge patch from Tim Waugh (via Nalin Dahyabhai <nalin@redhat.com>)
+   to fix NULL pointer deref and fake authloop breakage in PAM code.
+ - (bal) Updated contrib/cygwin/ by Corinna Vinschen <vinschen@redhat.com>
+ - (bal) Minor cygwin patch to auth1.c.  Suggested by djm.
+
+20010118
+ - (bal) Super Sized OpenBSD Resync
+   - markus@cvs.openbsd.org 2001/01/11 22:14:20 GMT 2001 by markus
+     [sshd.c]
+     maxfd+1
+   - markus@cvs.openbsd.org 2001/01/13 17:59:18
+     [ssh-keygen.1]
+     small ssh-keygen manpage cleanup; stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/13 18:03:07
+     [scp.c ssh-keygen.c sshd.c]
+     getopt() returns -1 not EOF; stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/13 18:06:54
+     [ssh-keyscan.c]
+     use SSH_DEFAULT_PORT; from stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/13 18:12:47
+     [ssh-keyscan.c]
+     free() -> xfree(); fix memory leak; from stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/13 18:14:13
+     [ssh-add.c]
+     typo, from stevesk@sweden.hp.com
+   - markus@cvs.openbsd.org 2001/01/13 18:32:50
+     [packet.c session.c ssh.c sshconnect.c sshd.c]
+     split out keepalive from packet_interactive (from dale@accentre.com)
+     set IPTOS_LOWDELAY TCP_NODELAY IPTOS_THROUGHPUT for ssh2, too.
+   - markus@cvs.openbsd.org 2001/01/13 18:36:45
+     [packet.c packet.h]
+     reorder, typo
+   - markus@cvs.openbsd.org 2001/01/13 18:38:00
+     [auth-options.c]
+     fix comment
+   - markus@cvs.openbsd.org 2001/01/13 18:43:31
+     [session.c]
+     Wall
+   - markus@cvs.openbsd.org 2001/01/13 19:14:08
+     [clientloop.h clientloop.c ssh.c]
+     move callback to headerfile
+   - markus@cvs.openbsd.org 2001/01/15 21:40:10
+     [ssh.c]
+     use log() instead of stderr
+   - markus@cvs.openbsd.org 2001/01/15 21:43:51
+     [dh.c]
+     use error() not stderr!
+   - markus@cvs.openbsd.org 2001/01/15 21:45:29
+     [sftp-server.c]
+     rename must fail if newpath exists, debug off by default
+   - markus@cvs.openbsd.org 2001/01/15 21:46:38
+     [sftp-server.c]
+     readable long listing for sftp-server, ok deraadt@
+   - markus@cvs.openbsd.org 2001/01/16 19:20:06
+     [key.c ssh-rsa.c]
+     make "ssh-rsa" key format for ssh2 confirm to the ietf-drafts; from
+     galb@vandyke.com.  note that you have to delete older ssh2-rsa keys,
+     since they are in the wrong format, too. they must be removed from
+     .ssh/authorized_keys2 and .ssh/known_hosts2, etc.
+     (cd; grep -v ssh-rsa .ssh/authorized_keys2 > TMP && mv TMP
+     .ssh/authorized_keys2) additionally, we now check that
+     BN_num_bits(rsa->n) >= 768.
+   - markus@cvs.openbsd.org 2001/01/16 20:54:27
+     [sftp-server.c]
+     remove some statics. simpler handles; idea from nisse@lysator.liu.se
+   - deraadt@cvs.openbsd.org 2001/01/16 23:58:08
+     [bufaux.c radix.c sshconnect.h sshconnect1.c]
+     indent
+ - (bal) Added bsd-strmode.[ch] since some non-OpenBSD platforms may
+   be missing such feature.
+
+
+20010117
+ - (djm) Only write random seed file at exit
+ - (djm) Make PAM support optional, enable with --with-pam
+ - (djm) Try to use libcrypt on Linux, but link it after OpenSSL (which
+   provides a crypt() of its own)
+ - (djm) Avoid a warning in bsd-bindresvport.c
+ - (djm) Try to avoid adding -I/usr/include to CPPFLAGS during SSL tests. This
+   can cause weird segfaults errors on Solaris
+ - (djm) Avoid warning in PAM code by making read_passphrase arguments const
+ - (djm) Add --with-pam to RPM spec files
+
+20010115
+ - (bal) sftp-server.c change to use chmod() if fchmod() does not exist.
+ - (bal) utimes() support via utime() interface on machine that lack utimes().
+
+20010114
+ - (stevesk) initial work for OpenBSD "support supplementary group in
+   {Allow,Deny}Groups" patch:
+   - import getgrouplist.c from OpenBSD (bsd-getgrouplist.c)
+   - add bsd-getgrouplist.h
+   - new files groupaccess.[ch]
+   - build but don't use yet (need to merge auth.c changes)
+ - (stevesk) complete:
+   - markus@cvs.openbsd.org  2001/01/13 11:56:48
+     [auth.c sshd.8]
+     support supplementary group in {Allow,Deny}Groups
+     from stevesk@pobox.com
+
+20010112
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/01/10 22:56:22
+     [bufaux.h bufaux.c sftp-server.c sftp.h getput.h]
+     cleanup sftp-server implementation:
+     add buffer_get_int64, buffer_put_int64, GET_64BIT, PUT_64BIT
+     parse SSH2_FILEXFER_ATTR_EXTENDED
+     send SSH2_FX_EOF if readdir returns no more entries
+     reply to SSH2_FXP_EXTENDED message
+     use #defines from the draft
+     move #definations to sftp.h
+     more info:
+     http://www.ietf.org/internet-drafts/draft-ietf-secsh-filexfer-00.txt
+   - markus@cvs.openbsd.org 2001/01/10 19:43:20
+     [sshd.c]
+     XXX - generate_empheral_server_key() is not safe against races,
+     because it calls log()
+   - markus@cvs.openbsd.org 2001/01/09 21:19:50
+     [packet.c]
+     allow TCP_NDELAY for ipv6; from netbsd via itojun@
+
+20010110
+ - (djm) SNI/Reliant Unix needs USE_PIPES and $DISPLAY hack. Report from
+   Bladt Norbert <Norbert.Bladt@adi.ch>
+
+20010109
+ - (bal) Resync CVS ID of cli.c
+ - (stevesk) auth1.c: free should be after WITH_AIXAUTHENTICATE
+   code.
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/01/08 22:29:05
+     [auth2.c compat.c compat.h servconf.c servconf.h sshd.8
+      sshd_config version.h]
+     implement option 'Banner /etc/issue.net' for ssh2, move version to
+     2.3.1 (needed for bugcompat detection, 2.3.0 would fail if Banner
+     is enabled).
+   - markus@cvs.openbsd.org 2001/01/08 22:03:23
+     [channels.c ssh-keyscan.c]
+     O_NDELAY -> O_NONBLOCK; thanks stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/08 21:55:41
+     [sshconnect1.c]
+     more cleanups and fixes from stevesk@pobox.com:
+     1) try_agent_authentication() for loop will overwrite key just
+        allocated with key_new(); don't alloc
+     2) call ssh_close_authentication_connection() before exit
+        try_agent_authentication()
+     3) free mem on bad passphrase in try_rsa_authentication()
+   - markus@cvs.openbsd.org 2001/01/08 21:48:17
+     [kex.c]
+     missing free; thanks stevesk@pobox.com
+  - (bal) Detect if clock_t structure exists, if not define it.
+  - (bal) Detect if O_NONBLOCK exists, if not define it.
+  - (bal) removed news4-posix.h (now empty)
+  - (bal) changed bsd-bindresvport.c and bsd-rresvport.c to use 'socklen_t'
+    instead of 'int'
+ - (stevesk) sshd_config: sync
+ - (stevesk) defines.h: remove spurious ``;''
+
+20010108
+ - (bal) Fixed another typo in cli.c
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/01/07 21:26:55
+     [cli.c]
+     typo
+   - markus@cvs.openbsd.org 2001/01/07 21:26:55
+     [cli.c]
+     missing free, stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/07 19:06:25
+     [auth1.c]
+     missing free, stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/07 11:28:04
+     [log-client.c log-server.c log.c readconf.c servconf.c ssh.1
+      ssh.h sshd.8 sshd.c]
+     rename SYSLOG_LEVEL_INFO->SYSLOG_LEVEL_NOTICE
+     syslog priority changes:
+             fatal() LOG_ERR  -> LOG_CRIT
+             log()   LOG_INFO -> LOG_NOTICE
+ - Updated TODO
+
+20010107
+ - (bal) OpenBSD Sync
+   - markus@cvs.openbsd.org 2001/01/06 11:23:27
+     [ssh-rsa.c]
+     remove unused
+   - itojun@cvs.openbsd.org 2001/01/05 08:23:29
+     [ssh-keyscan.1]
+     missing .El
+   - markus@cvs.openbsd.org 2001/01/04 22:41:03
+     [session.c sshconnect.c]
+     consistent use of _PATH_BSHELL; from stevesk@pobox.com
+   - djm@cvs.openbsd.org 2001/01/04 22:35:32
+     [ssh.1 sshd.8]
+     Mention AES as available SSH2 Cipher; ok markus
+   - markus@cvs.openbsd.org 2001/01/04 22:25:58
+     [sshd.c]
+     sync usage()/man with defaults; from stevesk@pobox.com
+   - markus@cvs.openbsd.org 2001/01/04 22:21:26
+     [sshconnect2.c]
+     handle SSH2_MSG_USERAUTH_BANNER; fixes bug when connecting to a server
+     that prints a banner (e.g. /etc/issue.net)
+
+20010105
+ - (bal) contrib/caldera/ provided by Tim Rice <tim@multitalents.net>
+ - (bal) bsd-getcwd.c and bsd-setenv.c changed from bcopy() to memmove()
+
+20010104
+ - (djm) Fix memory leak on systems with BROKEN_GETADDRINFO. Based on
+   work by Chris Vaughan <vaughan99@yahoo.com>
+
+20010103
+ - (bal) fixed up sshconnect.c so it was closer inline with the OpenBSD
+   tree (mainly positioning)
+ - (bal) OpenSSH CVS Update
+   - markus@cvs.openbsd.org 2001/01/02 20:41:02
+     [packet.c]
+     log remote ip on disconnect; PR 1600 from jcs@rt.fm
+   - markus@cvs.openbsd.org 2001/01/02 20:50:56
+     [sshconnect.c]
+     strict_host_key_checking for host_status != HOST_CHANGED &&
+     ip_status == HOST_CHANGED
+ - (bal) authfile.c: Synced CVS ID tag
+ - (bal) UnixWare 2.0 fixes by Tim Rice <tim@multitalents.net>
+ - (bal) Disable sftp-server if no 64bit int support exists.  Based on
+   patch by Tim Rice <tim@multitalents.net>
+ - (bal) Makefile.in changes to uninstall: target to remove sftp-server
+   and sftp-server.8 manpage.
+
+20010102
+ - (bal) OpenBSD CVS Update
+   - markus@cvs.openbsd.org 2001/01/01 14:52:49
+     [scp.c]
+     use shared fatal(); from stevesk@pobox.com
+
+20001231
+ - (bal) Reverted out of MAXHOSTNAMELEN.  This should be set per OS.
+   for multiple reasons.
+ - (bal) Reverted out of a partial NeXT patch.
+
+20001230
+ - (bal) OpenBSD CVS Update
+   - markus@cvs.openbsd.org 2000/12/28 18:58:30
+     [ssh-keygen.c]
+     enable 'ssh-keygen -l -f ~/.ssh/{authorized_keys,known_hosts}{,2}
+   - markus@cvs.openbsd.org 2000/12/29 22:19:13
+     [channels.c]
+     missing xfree; from vaughan99@yahoo.com
+ - (bal) Resynced CVS ID with OpenBSD for channel.c and uidswap.c
+ - (bal) if no MAXHOSTNAMELEN is defined.  Default to 64 character defination.
+   Suggested by Christian Kurz <shorty@debian.org>
+ - (bal) Add in '.c.o' section to Makefile.in to address make programs that
+    don't honor CPPFLAGS by default.  Suggested by Lutz Jaenicke
+    <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+
+20001229
+ - (bal) Fixed spelling of 'authorized_keys' in ssh-copy-id.1 by Christian
+   Kurz <shorty@debian.org>
+ - (bal) OpenBSD CVS Update
+   - markus@cvs.openbsd.org 2000/12/28 14:25:51
+     [auth.h auth2.c]
+     count authentication failures only
+   - markus@cvs.openbsd.org 2000/12/28 14:25:03
+     [sshconnect.c]
+     fingerprint for MITM attacks, too.
+   - markus@cvs.openbsd.org 2000/12/28 12:03:57
+     [sshd.8 sshd.c]
+     document -D
+   - markus@cvs.openbsd.org 2000/12/27 14:19:21
+     [serverloop.c]
+     less chatty
+   - markus@cvs.openbsd.org 2000/12/27 12:34
+     [auth1.c sshconnect2.c sshd.c]
+     typo
+   - markus@cvs.openbsd.org 2000/12/27 12:30:19
+     [readconf.c readconf.h ssh.1 sshconnect.c]
+     new option: HostKeyAlias: allow the user to record the host key
+     under a different name. This is useful for ssh tunneling over
+     forwarded connections or if you run multiple sshd's on different
+     ports on the same machine.
+   - markus@cvs.openbsd.org 2000/12/27 11:51:53
+     [ssh.1 ssh.c]
+     multiple -t force pty allocation, document ORIGINAL_COMMAND
+   - markus@cvs.openbsd.org 2000/12/27 11:41:31
+     [sshd.8]
+     update for ssh-2
+ - (stevesk) compress.[ch] sync with openbsd; missed in prototype
+   fix merge.
+
+20001228
+ - (bal) Patch to add libutil.h to loginrec.c only if the platform has
+   libutil.h.  Suggested by Pekka Savola <pekka@netcore.fi>
+ - (djm) Update to new x11-askpass in RPM spec
+ - (bal) SCO patch to not include <sys/queue.h> since it's unrelated
+   header.  Patch by Tim Rice <tim@multitalents.net>
+ - Updated TODO w/ known HP/UX issue
+ - (bal) removed extra <netdb.h> noticed by Kevin Steves and removed the
+   bad reference to 'NeXT including it else were' on the #ifdef version.
+
+20001227
+ - (bal) Typo in configure.in: entut?ent should be endut?ent.  Suggested by
+   Takumi Yamane <yamtak@b-session.com>
+ - (bal) Checks for getrlimit(), sysconf(), and setdtablesize().  Patch
+   by Corinna Vinschen <vinschen@redhat.com>
+ - (djm) Fix catman-do target for non-bash
+ - (bal) Typo in configure.in: entut?ent should be endut?ent.  Suggested by
+   Takumi Yamane <yamtak@b-session.com>
+ - (bal) Checks for getrlimit(), sysconf(), and setdtablesize().  Patch
+   by Corinna Vinschen <vinschen@redhat.com>
+ - (djm) Fix catman-do target for non-bash
+ - (bal) Fixed NeXT's lack of CPPFLAGS honoring.
+ - (bal) ssh-keyscan.c: NeXT (and older BSDs) don't support getrlimit() w/
+   'RLIMIT_NOFILE'
+ - (djm) Remove *.Ylonen files. They are no longer in the OpenBSD tree,
+   the info in COPYING.Ylonen has been moved to the start of each
+   SSH1-derived file and README.Ylonen is well out of date.
+
+20001223
+ - (bal) Fixed Makefile.in to support recompile of all ssh and sshd objects
+   if a change to config.h has occurred.  Suggested by Gert Doering
+   <gert@greenie.muc.de>
+ - (bal) OpenBSD CVS Update:
+   - markus@cvs.openbsd.org 2000/12/22 16:49:40
+     [ssh-keygen.c]
+     fix ssh-keygen -x -t type > file; from Roumen.Petrov@skalasoft.com
+
+20001222
+ - Updated RCSID for pty.c
+ - (bal) OpenBSD CVS Updates:
+  - markus@cvs.openbsd.org 2000/12/21 15:10:16
+    [auth-rh-rsa.c hostfile.c hostfile.h sshconnect.c]
+    print keyfile:line for changed hostkeys, for deraadt@, ok deraadt@
+  - markus@cvs.openbsd.org 2000/12/20 19:26:56
+    [authfile.c]
+    allow ssh -i userkey for root
+  - markus@cvs.openbsd.org 2000/12/20 19:37:21
+    [authfd.c authfd.h kex.c sshconnect2.c sshd.c uidswap.c uidswap.h]
+    fix prototypes; from stevesk@pobox.com
+  - markus@cvs.openbsd.org 2000/12/20 19:32:08
+    [sshd.c]
+    init pointer to NULL; report from Jan.Ivan@cern.ch
+  - markus@cvs.openbsd.org 2000/12/19 23:17:54
+    [auth-krb4.c auth-options.c auth-options.h auth-rhosts.c auth-rsa.c
+     auth1.c auth2-skey.c auth2.c authfd.c authfd.h authfile.c bufaux.c
+     bufaux.h buffer.c canohost.c channels.c clientloop.c compress.c
+     crc32.c deattack.c getput.h hmac.c hmac.h hostfile.c kex.c kex.h
+     key.c key.h log.c login.c match.c match.h mpaux.c mpaux.h packet.c
+     packet.h radix.c readconf.c rsa.c scp.c servconf.c servconf.h
+     serverloop.c session.c sftp-server.c ssh-agent.c ssh-dss.c ssh-dss.h
+     ssh-keygen.c ssh-keyscan.c ssh-rsa.c ssh-rsa.h ssh.c ssh.h  uuencode.c
+     uuencode.h sshconnect1.c sshconnect2.c sshd.c tildexpand.c]
+    replace 'unsigned bla' with 'u_bla' everywhere. also replace 'char
+    unsigned' with u_char.
+
+20001221
+ - (stevesk) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/19 15:43:45
+     [authfile.c channels.c sftp-server.c ssh-agent.c]
+     remove() -> unlink() for consistency
+   - markus@cvs.openbsd.org 2000/12/19 15:48:09
+     [ssh-keyscan.c]
+     replace <ssl/x.h> with <openssl/x.h>
+   - markus@cvs.openbsd.org 2000/12/17 02:33:40
+     [uidswap.c]
+     typo; from wsanchez@apple.com
+
+20001220
+ - (djm) Workaround PAM inconsistencies between Solaris derived PAM code
+   and Linux-PAM. Based on report and fix from Andrew Morgan
+   <morgan@transmeta.com>
+
+20001218
+ - (stevesk) rsa.c: entropy.h not needed.
+ - (bal) split CFLAGS into CFLAGS and CPPFLAGS in configure.in and Makefile.
+   Suggested by Wilfredo Sanchez <wsanchez@apple.com>
+
+20001216
+ - (stevesk) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/16 02:53:57
+     [scp.c]
+     allow + in usernames; request from Florian.Weimer@RUS.Uni-Stuttgart.DE
+   - markus@cvs.openbsd.org 2000/12/16 02:39:57
+     [scp.c]
+     unused; from stevesk@pobox.com
+
+20001215
+ - (stevesk) Old OpenBSD patch wasn't completely applied:
+   - markus@cvs.openbsd.org 2000/01/24 22:11:20
+     [scp.c]
+     allow '.' in usernames; from jedgar@fxp.org
+ - (stevesk) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/13 16:26:53
+     [ssh-keyscan.c]
+     fatal already adds \n; from stevesk@pobox.com
+   - markus@cvs.openbsd.org 2000/12/13 16:25:44
+     [ssh-agent.c]
+     remove redundant spaces; from stevesk@pobox.com
+   - ho@cvs.openbsd.org 2000/12/12 15:50:21
+     [pty.c]
+     When failing to set tty owner and mode on a read-only filesystem, don't
+     abort if the tty already has correct owner and reasonably sane modes.
+     Example; permit 'root' to login to a firewall with read-only root fs.
+     (markus@ ok)
+   - deraadt@cvs.openbsd.org 2000/12/13 06:36:05
+     [pty.c]
+     KNF
+   - markus@cvs.openbsd.org 2000/12/12 14:45:21
+     [sshd.c]
+     source port < 1024 is no longer required for rhosts-rsa since it
+     adds no additional security.
+   - markus@cvs.openbsd.org 2000/12/12 16:11:49
+     [ssh.1 ssh.c]
+     rhosts-rsa is no longer automagically disabled if ssh is not privileged.
+     UsePrivilegedPort=no disables rhosts-rsa _only_ for old servers.
+     these changes should not change the visible default behaviour of the ssh client.
+   - deraadt@cvs.openbsd.org 2000/12/11 10:27:33
+     [scp.c]
+     when copying 0-sized files, do not re-print ETA time at completion
+   - provos@cvs.openbsd.org 2000/12/15 10:30:15
+     [kex.c kex.h sshconnect2.c sshd.c]
+     compute diffie-hellman in parallel between server and client. okay markus@
+
+20001213
+ - (djm) Make sure we reset the SIGPIPE disposition after we fork. Report
+   from Andreas M. Kirchwitz <amk@krell.zikzak.de>
+ - (stevesk) OpenBSD CVS update:
+   - markus@cvs.openbsd.org 2000/12/12 15:30:02
+     [ssh-keyscan.c ssh.c sshd.c]
+     consistently use __progname; from stevesk@pobox.com
+
+20001211
+ - (bal) Applied patch to include ssh-keyscan into Redhat's package, and
+   patch to install ssh-keyscan manpage.  Patch by Pekka Savola
+   <pekka@netcore.fi>
+ - (bal) OpenbSD CVS update
+   - markus@cvs.openbsd.org 2000/12/10 17:01:53
+     [sshconnect1.c]
+     always request new challenge for skey/tis-auth, fixes interop with
+     other implementations; report from roth@feep.net
+
+20001210
+ - (bal) OpenBSD CVS updates
+   - markus@cvs.openbsd.org 2000/12/09 13:41:51
+     [cipher.c cipher.h rijndael.c rijndael.h rijndael_boxes.h]
+     undo rijndael changes
+   - markus@cvs.openbsd.org 2000/12/09 13:48:31
+     [rijndael.c]
+     fix byte order bug w/o introducing new implementation
+   - markus@cvs.openbsd.org 2000/12/09 14:08:27
+     [sftp-server.c]
+     "" -> "." for realpath; from vinschen@redhat.com
+   - markus@cvs.openbsd.org 2000/12/09 14:06:54
+     [ssh-agent.c]
+     extern int optind; from stevesk@sweden.hp.com
+   - provos@cvs.openbsd.org 2000/12/09 23:51:11
+     [compat.c]
+     remove unnecessary '\n'
+
+20001209
+ - (bal) OpenBSD CVS updates:
+   - djm@cvs.openbsd.org 2000/12/07 4:24:59
+     [ssh.1]
+     Typo fix from Wilfredo Sanchez <wsanchez@apple.com>; ok theo
+
+20001207
+ - (bal) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/06 22:58:14
+     [compat.c compat.h packet.c]
+     disable debug messages for ssh.com/f-secure 2.0.1x, 2.1.0
+   - markus@cvs.openbsd.org 2000/12/06 23:10:39
+     [rijndael.c]
+     unexpand(1)
+   - markus@cvs.openbsd.org 2000/12/06 23:05:43
+     [cipher.c cipher.h rijndael.c rijndael.h rijndael_boxes.h]
+     new rijndael implementation. fixes endian bugs
+
+20001206
+ - (bal) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/05 20:34:09
+     [channels.c channels.h clientloop.c serverloop.c]
+     async connects for -R/-L; ok deraadt@
+   - todd@cvs.openssh.org 2000/12/05 16:47:28
+     [sshd.c]
+     tweak comment to reflect real location of pid file; ok provos@
+ - (stevesk) Import <sys/queue.h> from OpenBSD for systems that don't
+   have it (used in ssh-keyscan).
+ - (stevesk) OpenBSD CVS update:
+   - markus@cvs.openbsd.org 2000/12/06 19:57:48
+     [ssh-keyscan.c]
+     err(3) -> internal error(), from stevesk@sweden.hp.com
+
+20001205
+ - (bal) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/04 19:24:02
+     [ssh-keyscan.c ssh-keyscan.1]
+     David Maziere's ssh-keyscan, ok niels@
+ - (bal) Updated Makefile.in to include ssh-keyscan that was just added
+   to the recent OpenBSD source tree.
+ - (stevesk) fix typos in contrib/hpux/README
+
+20001204
+ - (bal) More C functions defined in NeXT that are unaccessable without
+   defining -POSIX.
+ - (bal) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org 2000/12/03 11:29:04
+     [compat.c]
+     remove fallback to SSH_BUG_HMAC now that the drafts are updated
+   - markus@cvs.openbsd.org 2000/12/03 11:27:55
+     [compat.c]
+     correctly match "2.1.0.pl2 SSH" etc; from
+     pekkas@netcore.fi/bugzilla.redhat
+   - markus@cvs.openbsd.org 2000/12/03 11:15:03
+     [auth2.c compat.c compat.h sshconnect2.c]
+     support f-secure/ssh.com 2.0.12; ok niels@
+
+20001203
+ - (bal) OpenBSD CVS updates:
+  - markus@cvs.openbsd.org 2000/11/30 22:54:31
+    [channels.c]
+    debug->warn if tried to do -R style fwd w/o client requesting this;
+    ok neils@
+  - markus@cvs.openbsd.org 2000/11/29 20:39:17
+    [cipher.c]
+    des_cbc_encrypt -> des_ncbc_encrypt since it already updates the IV
+  - markus@cvs.openbsd.org 2000/11/30 18:33:05
+    [ssh-agent.c]
+    agents must not dump core, ok niels@
+  - markus@cvs.openbsd.org 2000/11/30 07:04:02
+    [ssh.1]
+    T is for both protocols
+  - markus@cvs.openbsd.org 2000/12/01 00:00:51
+    [ssh.1]
+    typo; from green@FreeBSD.org
+  - markus@cvs.openbsd.org 2000/11/30 07:02:35
+    [ssh.c]
+    check -T before isatty()
+  - provos@cvs.openbsd.org 2000/11/29 13:51:27
+    [sshconnect.c]
+    show IP address and hostname when new key is encountered. okay markus@
+  - markus@cvs.openbsd.org 2000/11/30 22:53:35
+    [sshconnect.c]
+    disable agent/x11/port fwding if hostkey has changed; ok niels@
+  - marksu@cvs.openbsd.org 2000/11/29 21:11:59
+    [sshd.c]
+    sshd -D, startup w/o deamon(), for monitoring scripts or inittab;
+    from handler@sub-rosa.com and eric@urbanrange.com; ok niels@
+ - (djm) Added patch from Nalin Dahyabhai <nalin@redhat.com> to enable
+   PAM authentication using KbdInteractive.
+ - (djm) Added another TODO
+
+20001202
+ - (bal) Backed out of part of Alain St-Denis' loginrec.c patch.
+ - (bal) Irix need some sort of mansubdir, patch by Michael Stone
+   <mstone@cs.loyola.edu>
+
+20001129
+ - (djm) Back out all the serverloop.c hacks. sshd will now hang again
+   if there are background children with open fds.
+ - (djm) bsd-rresvport.c bzero -> memset
+ - (djm) Don't fail in defines.h on absence of 64 bit types (we will
+   still fail during compilation of sftp-server).
+ - (djm) Fail if ar is not found during configure
+ - (djm) OpenBSD CVS updates:
+   - provos@cvs.openbsd.org  2000/11/22 08:38:31
+     [sshd.8]
+     talk about /etc/primes, okay markus@
+   - markus@cvs.openbsd.org  2000/11/23 14:03:48
+     [ssh.c sshconnect1.c sshconnect2.c]
+     complain about invalid ciphers for ssh1/ssh2, fall back to reasonable
+     defaults
+   - markus@cvs.openbsd.org  2000/11/25 09:42:53
+     [sshconnect1.c]
+     reorder check for illegal ciphers, bugreport from espie@
+   - markus@cvs.openbsd.org  2000/11/25 10:19:34
+     [ssh-keygen.c ssh.h]
+     print keytype when generating a key.
+     reasonable defaults for RSA1/RSA/DSA keys.
+ - (djm) Patch from Pekka Savola <Pekka.Savola@netcore.fi> to include a few
+   more manpage paths in fixpaths calls
+ - (djm) Also add xauth path at Pekka's suggestion.
+ - (djm) Add Redhat RPM patch for AUTHPRIV SyslogFacility
+
+20001125
+ - (djm) Give up privs when reading seed file
+
+20001123
+ - (bal) Merge OpenBSD changes:
+   - markus@cvs.openbsd.org  2000/11/15 22:31:36
+     [auth-options.c]
+     case insensitive key options; from stevesk@sweeden.hp.com
+   - markus@cvs.openbsd.org  2000/11/16 17:55:43
+     [dh.c]
+     do not use perror() in sshd, after child is forked()
+   - markus@cvs.openbsd.org  2000/11/14 23:42:40
+     [auth-rsa.c]
+     parse option only if key matches; fix some confusing seen by the client
+   - markus@cvs.openbsd.org  2000/11/14 23:44:19
+     [session.c]
+     check no_agent_forward_flag for ssh-2, too
+   - markus@cvs.openbsd.org  2000/11/15
+     [ssh-agent.1]
+     reorder SYNOPSIS; typo, use .It
+   - markus@cvs.openbsd.org  2000/11/14 23:48:55
+     [ssh-agent.c]
+     do not reorder keys if a key is removed
+   - markus@cvs.openbsd.org  2000/11/15 19:58:08
+     [ssh.c]
+     just ignore non existing user keys
+   - millert@cvs.openbsd.org  200/11/15 20:24:43
+     [ssh-keygen.c]
+     Add missing \n at end of error message.
+
+20001122
+ - (bal) Minor patch to ensure platforms lacking IRIX job limit supports
+   are compilable.
+ - (bal) Updated TODO as of 11/18/2000 with known things to resolve.
+
+20001117
+ - (bal) Changed from 'primes' to 'primes.out' for consistancy sake.  It
+   has no affect the output.  Patch by Corinna Vinschen <vinschen@redhat.com>
+ - (stevesk) Reworked progname support.
+ - (bal) Misplaced #include "includes.h" in bsd-setproctitle.c.  Patch by
+   Shinichi Maruyama <marya@st.jip.co.jp>
+
+20001116
+ - (bal) Added in MAXSYMLINK test in bsd-realpath.c.  Required for some SCO
+   releases.
+ - (bal) Make builds work outside of source tree.  Patch by Mark D. Roth
+   <roth@feep.net>
+
+20001113
+ - (djm) Add pointer to http://www.imasy.or.jp/~gotoh/connect.c to
+   contrib/README
+ - (djm) Merge OpenBSD changes:
+   - markus@cvs.openbsd.org  2000/11/06 16:04:56
+     [channels.c channels.h clientloop.c nchan.c serverloop.c]
+     [session.c ssh.c]
+     agent forwarding and -R for ssh2, based on work from
+     jhuuskon@messi.uku.fi
+   - markus@cvs.openbsd.org  2000/11/06 16:13:27
+     [ssh.c sshconnect.c sshd.c]
+     do not disabled rhosts(rsa) if server port > 1024; from
+     pekkas@netcore.fi
+   - markus@cvs.openbsd.org  2000/11/06 16:16:35
+     [sshconnect.c]
+     downgrade client to 1.3 if server is 1.4; help from mdb@juniper.net
+   - markus@cvs.openbsd.org  2000/11/09 18:04:40
+     [auth1.c]
+     typo; from mouring@pconline.com
+   - markus@cvs.openbsd.org  2000/11/12 12:03:28
+     [ssh-agent.c]
+     off-by-one when removing a key from the agent
+   - markus@cvs.openbsd.org  2000/11/12 12:50:39
+     [auth-rh-rsa.c auth2.c authfd.c authfd.h]
+     [authfile.c hostfile.c kex.c kex.h key.c key.h myproposal.h]
+     [readconf.c readconf.h rsa.c rsa.h servconf.c servconf.h ssh-add.c]
+     [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config]
+     [sshconnect1.c sshconnect2.c sshd.8 sshd.c sshd_config ssh-dss.c]
+     [ssh-dss.h ssh-rsa.c ssh-rsa.h dsa.c dsa.h]
+     add support for RSA to SSH2.  please test.
+     there are now 3 types of keys: RSA1 is used by ssh-1 only,
+     RSA and DSA are used by SSH2.
+     you can use 'ssh-keygen -t rsa -f ssh2_rsa_file' to generate RSA
+     keys for SSH2 and use the RSA keys for hostkeys or for user keys.
+     SSH2 RSA or DSA keys are added to .ssh/authorised_keys2 as before.
+ - (djm) Fix up Makefile and Redhat init script to create RSA host keys
+ - (djm) Change to interim version
+ - (djm) Fix RPM spec file stupidity
+ - (djm) fixpaths to DSA and RSA keys too
+
+20001112
+ - (bal) SCO Patch to add needed libraries for configure.in.  Patch by
+   Phillips Porch <root@theporch.com>
+ - (bal) IRIX patch to adding Job Limits.  Patch by Denis Parker
+   <dcp@sgi.com>
+ - (stevesk) pty.c: HP-UX 10 and 11 don't define TIOCSCTTY.  Add error() to
+   failed ioctl(TIOCSCTTY) call.
+
+20001111
+ - (djm) Added /etc/primes for kex DH group neg, fixup Makefile.in and
+   packaging files
+ - (djm) Fix new Makefile.in warnings
+ - (djm) Fix vsprintf("%h") in bsd-snprintf.c, short int va_args are
+   promoted to type int. Report and fix from Dan Astoorian
+   <djast@cs.toronto.edu>
+ - (djm) Hardwire sysconfdir in RPM spec files as some RPM versions get
+   it wrong. Report from Bennett Todd <bet@rahul.net>
+
+20001110
+ - (bal) Fixed dropped answer from skey_keyinfo() in auth1.c
+ - (bal) Changed from --with-skey to --with-skey=PATH in configure.in
+ - (bal) Added in check to verify S/Key library is being detected in
+   configure.in
+ - (bal) next-posix.h - added another prototype wrapped in POSIX ifdef/endif.
+   Patch by Mark Miller <markm@swoon.net>
+ - (bal) Added 'util.h' header to loginrec.c only if HAVE_UTIL_H is defined
+   to remove warnings under MacOS X.  Patch by Mark Miller <markm@swoon.net>
+ - (bal) Fixed LDFLAG mispelling in configure.in for --with-afs
+
+20001107
+ - (bal) acconfig.in - removed the double "USE_PIPES" entry. Patch by
+   Mark Miller <markm@swoon.net>
+ - (bal) sshd.init files corrected to assign $? to RETVAL.  Patch by
+   Jarno Huuskonen <jhuuskon@messi.uku.fi>
+ - (bal) fixpaths fixed to stop it from quitely failing. Patch by
+   Mark D. Roth <roth@feep.net>
+
+20001106
+ - (djm) Use Jim's new 1.0.3 askpass in Redhat RPMs
+ - (djm) Manually fix up missed diff hunks (mainly RCS idents)
+ - (djm) Remove UPGRADING document in favour of a link to the better
+   maintained FAQ on www.openssh.com
+ - (djm) Fix multiple dependancy on gnome-libs from Pekka Savola
+   <pekkas@netcore.fi>
+ - (djm) Don't need X11-askpass in RPM spec file if building without it
+   from Pekka Savola <pekkas@netcore.fi>
+ - (djm) Release 2.3.0p1
+ - (bal) typo in configure.in in regards to --with-ldflags from Marko
+   Asplund <aspa@kronodoc.fi>
+ - (bal) fixed next-posix.h.  Forgot prototype of getppid().
+
+20001105
+ - (bal) Sync with OpenBSD:
+   - markus@cvs.openbsd.org 2000/10/31 9:31:58
+     [compat.c]
+     handle all old openssh versions
+   - markus@cvs.openbsd.org 2000/10/31 13:1853
+     [deattack.c]
+     so that large packets do not wrap "n"; from netbsd
+ - (bal) rijndel.c - fix up RCSID to match OpenBSD tree
+ - (bal) auth2-skey.c - Checked in.  Missing from portable tree.
+ - (bal) Reworked NEWS-OS and NeXT ports to extract waitpid() and
+   setsid() into more common files
+ - (stevesk) pty.c: use __hpux to identify HP-UX.
+ - (bal) Missed auth-skey.o in Makefile.in and minor correction to
+   bsd-waitpid.c
+
+20001029
+ - (stevesk) Fix typo in auth.c: USE_PAM not PAM
+ - (stevesk) Create contrib/cygwin/ directory; patch from
+   Corinna Vinschen <vinschen@redhat.com>
+ - (bal) Resolved more $xno and $xyes issues in configure.in
+ - (bal) next-posix.h - spelling and forgot a prototype
+
+20001028
+ - (djm) fix select hack in serverloop.c from Philippe WILLEM
+   <Philippe.WILLEM@urssaf.fr>
+ - (djm) Fix mangled AIXAUTHENTICATE code
+ - (djm) authctxt->pw may be NULL. Fix from Markus Friedl
+   <markus.friedl@informatik.uni-erlangen.de>
+ - (djm) Sync with OpenBSD:
+   - markus@cvs.openbsd.org  2000/10/16 15:46:32
+     [ssh.1]
+     fixes from pekkas@netcore.fi
+   - markus@cvs.openbsd.org  2000/10/17 14:28:11
+     [atomicio.c]
+     return number of characters processed; ok deraadt@
+   - markus@cvs.openbsd.org  2000/10/18 12:04:02
+     [atomicio.c]
+     undo
+   - markus@cvs.openbsd.org  2000/10/18 12:23:02
+     [scp.c]
+     replace atomicio(read,...) with read(); ok deraadt@
+   - markus@cvs.openbsd.org  2000/10/18 12:42:00
+     [session.c]
+     restore old record login behaviour
+   - deraadt@cvs.openbsd.org 2000/10/19 10:41:13
+     [auth-skey.c]
+     fmt string problem in unused code
+   - provos@cvs.openbsd.org  2000/10/19 10:45:16
+     [sshconnect2.c]
+     don't reference freed memory. okay deraadt@
+   - markus@cvs.openbsd.org  2000/10/21 11:04:23
+     [canohost.c]
+     typo, eramore@era-t.ericsson.se; ok niels@
+   - markus@cvs.openbsd.org  2000/10/23 13:31:55
+     [cipher.c]
+     non-alignment dependent swap_bytes(); from
+     simonb@wasabisystems.com/netbsd
+   - markus@cvs.openbsd.org  2000/10/26 12:38:28
+     [compat.c]
+     add older vandyke products
+   - markus@cvs.openbsd.org  2000/10/27 01:32:19
+     [channels.c channels.h clientloop.c serverloop.c session.c]
+     [ssh.c util.c]
+     enable non-blocking IO on channels, and tty's (except for the
+     client ttys).
+
+20001027
+ - (djm) Increase REKEY_BYTES to 2^24 for arc4random
+
+20001025
+ - (djm) Added WARNING.RNG file and modified configure to ask users of the
+   builtin entropy code to read it.
+ - (djm) Prefer builtin regex to PCRE.
+ - (bal) Added USE_PIPS defined to NeXT configure.in since scp hangs randomly.
+ - (bal) Apply fixes to configure.in pointed out by Pavel Roskin
+   <proski@gnu.org>
+
+20001020
+ - (djm) Don't define _REENTRANT for SNI/Reliant Unix
+ - (bal) Imported NEWS-OS waitpid() macros into NeXT.  Since implementation
+   is more correct then current version.
+
+20001018
+ - (stevesk) Add initial support for setproctitle().  Current
+   support is for the HP-UX pstat(PSTAT_SETCMD, ...) method.
+ - (stevesk) Add egd startup scripts to contrib/hpux/
+
+20001017
+ - (djm) Add -lregex to cywin libs from Corinna Vinschen
+   <vinschen@cygnus.com>
+ - (djm) Don't rely on atomicio's retval to determine length of askpass
+   supplied passphrase. Problem report from Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - (bal) Changed from GNU rx to PCRE on suggestion from djm.
+ - (bal) Integrated Sony NEWS-OS patches from NAKAJI Hirouyuki
+   <nakaji@tutrp.tut.ac.jp>
+
+20001016
+ - (djm) Sync with OpenBSD:
+   - markus@cvs.openbsd.org  2000/10/14 04:01:15
+     [cipher.c]
+     debug3
+   - markus@cvs.openbsd.org  2000/10/14 04:07:23
+     [scp.c]
+     remove spaces from arguments; from djm@mindrot.org
+   - markus@cvs.openbsd.org  2000/10/14 06:09:46
+     [ssh.1]
+     Cipher is for SSH-1 only
+   - markus@cvs.openbsd.org  2000/10/14 06:12:09
+     [servconf.c servconf.h serverloop.c session.c sshd.8]
+     AllowTcpForwarding; from naddy@
+   - markus@cvs.openbsd.org  2000/10/14 06:16:56
+     [auth2.c compat.c compat.h sshconnect2.c version.h]
+     OpenSSH_2.3; note that is is not complete, but the version number
+     needs to be changed for interoperability reasons
+   - markus@cvs.openbsd.org  2000/10/14 06:19:45
+     [auth-rsa.c]
+     do not send RSA challenge if key is not allowed by key-options; from
+     eivind@ThinkSec.com
+   - markus@cvs.openbsd.org  2000/10/15 08:14:01
+     [rijndael.c session.c]
+     typos; from stevesk@sweden.hp.com
+   - markus@cvs.openbsd.org  2000/10/15 08:18:31
+     [rijndael.c]
+     typo
+ - (djm) Copy manpages back over from OpenBSD - too tedious to wade
+   through diffs
+ - (djm) Added condrestart to Redhat init script. Patch from Pekka Savola
+   <pekkas@netcore.fi>
+ - (djm) Update version in Redhat spec file
+ - (djm) Merge some of Nalin Dahyabhai <nalin@redhat.com> changes from the
+   Redhat 7.0 spec file
+ - (djm) Make inability to read/write PRNG seedfile non-fatal
+
+
+20001015
+ - (djm) Fix ssh2 hang on background processes at logout.
+
+20001014
+ - (bal) Add support for realpath and getcwd for platforms with broken
+   or missing realpath implementations for sftp-server.
+ - (bal) Corrected mistake in INSTALL in regards to GNU rx library
+ - (bal) Add support for GNU rx library for those lacking regexp support
+ - (djm) Don't accept PAM_PROMPT_ECHO_ON messages during initial auth
+ - (djm) Revert SSH2 serverloop hack, will find a better way.
+ - (djm) Add workaround for Linux 2.4's gratuitious errno change. Patch
+   from Martin Johansson <fatbob@acc.umu.se>
+ - (djm) Big OpenBSD sync:
+   - markus@cvs.openbsd.org  2000/09/30 10:27:44
+     [log.c]
+     allow loglevel debug
+   - markus@cvs.openbsd.org  2000/10/03 11:59:57
+     [packet.c]
+     hmac->mac
+   - markus@cvs.openbsd.org  2000/10/03 12:03:03
+     [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c]
+     move fake-auth from auth1.c to individual auth methods, disables s/key in
+     debug-msg
+   - markus@cvs.openbsd.org  2000/10/03 12:16:48
+     ssh.c
+     do not resolve canonname, i have no idea why this was added oin ossh
+   - markus@cvs.openbsd.org  2000/10/09 15:30:44
+     ssh-keygen.1 ssh-keygen.c
+     -X now reads private ssh.com DSA keys, too.
+   - markus@cvs.openbsd.org  2000/10/09 15:32:34
+     auth-options.c
+     clear options on every call.
+   - markus@cvs.openbsd.org  2000/10/09 15:51:00
+     authfd.c authfd.h
+     interop with ssh-agent2, from <res@shore.net>
+   - markus@cvs.openbsd.org  2000/10/10 14:20:45
+     compat.c
+     use rexexp for version string matching
+   - provos@cvs.openbsd.org  2000/10/10 22:02:18
+     [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h]
+     First rough implementation of the diffie-hellman group exchange.  The
+     client can ask the server for bigger groups to perform the diffie-hellman
+     in, thus increasing the attack complexity when using ciphers with longer
+     keys.  University of Windsor provided network, T the company.
+   - markus@cvs.openbsd.org  2000/10/11 13:59:52
+     [auth-rsa.c auth2.c]
+     clear auth options unless auth sucessfull
+   - markus@cvs.openbsd.org  2000/10/11 14:00:27
+     [auth-options.h]
+     clear auth options unless auth sucessfull
+   - markus@cvs.openbsd.org  2000/10/11 14:03:27
+     [scp.1 scp.c]
+     support 'scp -o' with help from mouring@pconline.com
+   - markus@cvs.openbsd.org  2000/10/11 14:11:35
+     [dh.c]
+     Wall
+   - markus@cvs.openbsd.org  2000/10/11 14:14:40
+     [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h]
+     [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h]
+     add support for s/key (kbd-interactive) to ssh2, based on work by
+     mkiernan@avantgo.com and me
+   - markus@cvs.openbsd.org  2000/10/11 14:27:24
+     [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h]
+     [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c]
+     [sshconnect2.c sshd.c]
+     new cipher framework
+   - markus@cvs.openbsd.org  2000/10/11 14:45:21
+     [cipher.c]
+     remove DES
+   - markus@cvs.openbsd.org  2000/10/12 03:59:20
+     [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c]
+     enable DES in SSH-1 clients only
+   - markus@cvs.openbsd.org  2000/10/12 08:21:13
+     [kex.h packet.c]
+     remove unused
+   - markus@cvs.openbsd.org  2000/10/13 12:34:46
+     [sshd.c]
+     Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se
+   - markus@cvs.openbsd.org  2000/10/13 12:59:15
+     [cipher.c cipher.h myproposal.h  rijndael.c rijndael.h]
+     rijndael/aes support
+   - markus@cvs.openbsd.org  2000/10/13 13:10:54
+     [sshd.8]
+     more info about -V
+   - markus@cvs.openbsd.org  2000/10/13 13:12:02
+     [myproposal.h]
+     prefer no compression
+ - (djm) Fix scp user@host handling
+ - (djm) Don't clobber ssh_prng_cmds on install
+ - (stevesk) Include config.h in rijndael.c so we define intXX_t and
+   u_intXX_t types on all platforms.
+ - (stevesk) rijndael.c: cleanup missing declaration warnings.
+ - (stevesk) ~/.hushlogin shouldn't cause required password change to
+   be bypassed.
+ - (stevesk) Display correct path to ssh-askpass in configure output.
+   Report from Lutz Jaenicke.
+
+20001007
+ - (stevesk) Print PAM return value in PAM log messages to aid
+   with debugging.
+ - (stevesk) Fix detection of pw_class struct member in configure;
+   patch from KAMAHARA Junzo <kamahara@cc.kshosen.ac.jp>
+
+20001002
+ - (djm) Fix USER_PATH, report from Kevin Steves <stevesk@sweden.hp.com>
+ - (djm) Add host system and CC to end-of-configure report. Suggested by
+   Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+
+20000931
+ - (djm) Cygwin fixes from Corinna Vinschen <vinschen@cygnus.com>
+
+20000930
+ - (djm) Irix ssh_prng_cmds path fix from Pekka Savola <pekkas@netcore.fi>
+ - (djm) Support in bsd-snprintf.c for long long conversions from
+   Ben Lindstrom <mouring@pconline.com>
+ - (djm) Cleanup NeXT support from Ben Lindstrom <mouring@pconline.com>
+ - (djm) Ignore SIGPIPEs from serverloop to child. Fixes crashes with
+   very short lived X connections. Bug report from Tobias Oetiker
+   <oetiker@ee.ethz.ch>. Fix from Markus Friedl <markus@cvs.openbsd.org>
+ - (djm) Add recent InitScripts as a RPM dependancy for openssh-server
+   patch from Pekka Savola <pekkas@netcore.fi>
+ - (djm) Forgot to cvs add LICENSE file
+ - (djm) Add LICENSE to RPM spec files
+ - (djm) CVS OpenBSD sync:
+   - markus@cvs.openbsd.org  2000/09/26 13:59:59
+     [clientloop.c]
+     use debug2
+   - markus@cvs.openbsd.org  2000/09/27 15:41:34
+     [auth2.c sshconnect2.c]
+     use key_type()
+   - markus@cvs.openbsd.org  2000/09/28 12:03:18
+     [channels.c]
+     debug -> debug2 cleanup
+ - (djm) Irix strips "/dev/tty" from [uw]tmp entries (other systems only
+   strip "/dev/"). Fix loginrec.c based on patch from Alain St-Denis
+   <Alain.St-Denis@ec.gc.ca>
+ - (djm) Fix 9 character passphrase failure with gnome-ssh-askpass.
+   Problem was caused by interrupted read in ssh-add. Report from Donald
+   J. Barry <don@astro.cornell.edu>
+
+20000929
+ - (djm) Fix SSH2 not terminating until all background tasks done problem.
+ - (djm) Another off-by-one fix from Pavel Kankovsky
+   <peak@argo.troja.mff.cuni.cz>
+ - (djm) Clean up. Strip some unnecessary differences with OpenBSD's code,
+   tidy necessary differences. Use Markus' new debugN() in entropy.c
+ - (djm) Merged big SCO portability patch from Tim Rice
+   <tim@multitalents.net>
+
+20000926
+ - (djm) Update X11-askpass to 1.0.2 in RPM spec file
+ - (djm) Define _REENTRANT to pickup strtok_r() on HP/UX
+ - (djm) Security: fix off-by-one buffer overrun in fake-getnameinfo.c.
+   Report and fix from Pavel Kankovsky <peak@argo.troja.mff.cuni.cz>
+
+20000924
+ - (djm) Merged cleanup patch from Mark Miller <markm@swoon.net>
+ - (djm) A bit more cleanup - created cygwin_util.h
+ - (djm) Include strtok_r() from OpenBSD libc. Fixes report from Mark Miller
+   <markm@swoon.net>
+
+20000923
+ - (djm) Fix address logging in utmp from Kevin Steves
+   <stevesk@sweden.hp.com>
+ - (djm) Redhat spec and manpage fixes from Pekka Savola <pekkas@netcore.fi>
+ - (djm) Seperate tests for int64_t and u_int64_t types
+ - (djm) Tweak password expiry checking at suggestion of Kevin Steves
+   <stevesk@sweden.hp.com>
+ - (djm) NeXT patch from Ben Lindstrom <mouring@pconline.com>
+ - (djm) Use printf %lld instead of %qd in sftp-server.c. Fix from
+   Michael Stone <mstone@cs.loyola.edu>
+ - (djm) OpenBSD CVS sync:
+   - markus@cvs.openbsd.org  2000/09/17 09:38:59
+     [sshconnect2.c sshd.c]
+     fix DEBUG_KEXDH
+   - markus@cvs.openbsd.org  2000/09/17 09:52:51
+     [sshconnect.c]
+     yes no; ok niels@
+   - markus@cvs.openbsd.org  2000/09/21 04:55:11
+     [sshd.8]
+     typo
+   - markus@cvs.openbsd.org  2000/09/21 05:03:54
+     [serverloop.c]
+     typo
+   - markus@cvs.openbsd.org  2000/09/21 05:11:42
+     scp.c
+     utime() to utimes(); mouring@pconline.com
+   - markus@cvs.openbsd.org  2000/09/21 05:25:08
+     sshconnect2.c
+     change login logic in ssh2, allows plugin of other auth methods
+   - markus@cvs.openbsd.org  2000/09/21 05:25:35
+     [auth2.c channels.c channels.h clientloop.c dispatch.c dispatch.h]
+     [serverloop.c]
+     add context to dispatch_run
+   - markus@cvs.openbsd.org  2000/09/21 05:07:52
+     authfd.c authfd.h ssh-agent.c
+     bug compat for old ssh.com software
+
+20000920
+ - (djm) Fix bad path substitution. Report from Andrew Miner
+   <asminer@cs.iastate.edu>
+
+20000916
+ - (djm) Fix SSL search order from Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - (djm) New SuSE spec from Corinna Vinschen <corinna@vinschen.de>
+ - (djm) Update CygWin support from Corinna Vinschen <vinschen@cygnus.com>
+ - (djm) Use a real struct sockaddr inside the fake struct sockaddr_storage.
+   Patch from Larry Jones <larry.jones@sdrc.com>
+ - (djm) Add Steve VanDevender's <stevev@darkwing.uoregon.edu> PAM
+   password change patch.
+ - (djm) Bring licenses on my stuff in line with OpenBSD's
+ - (djm) Cleanup auth-passwd.c and unify HP/UX authentication. Patch from
+   Kevin Steves <stevesk@sweden.hp.com>
+ - (djm) Shadow expiry check fix from Pavel Troller <patrol@omni.sinus.cz>
+ - (djm) Re-enable int64_t types - we need them for sftp
+ - (djm) Use libexecdir from configure , rather than libexecdir/ssh
+ - (djm) Update Redhat SPEC file accordingly
+ - (djm) Add Kevin Steves <stevesk@sweden.hp.com> HP/UX contrib files
+ - (djm) Add Charles Levert <charles@comm.polymtl.ca> getpgrp patch
+ - (djm) Fix password auth on HP/UX 10.20. Patch from Dirk De Wachter
+   <Dirk.DeWachter@rug.ac.be>
+ - (djm) Fixprogs and entropy list fixes from Larry Jones
+   <larry.jones@sdrc.com>
+ - (djm) Fix for SuSE spec file from Takashi YOSHIDA
+   <tyoshida@gemini.rc.kyushu-u.ac.jp>
+ - (djm) Merge OpenBSD changes:
+   - markus@cvs.openbsd.org  2000/09/05 02:59:57
+     [session.c]
+     print hostname (not hushlogin)
+   - markus@cvs.openbsd.org  2000/09/05 13:18:48
+     [authfile.c ssh-add.c]
+     enable ssh-add -d for DSA keys
+   - markus@cvs.openbsd.org  2000/09/05 13:20:49
+     [sftp-server.c]
+     cleanup
+   - markus@cvs.openbsd.org  2000/09/06 03:46:41
+     [authfile.h]
+     prototype
+   - deraadt@cvs.openbsd.org 2000/09/07 14:27:56
+     [ALL]
+     cleanup copyright notices on all files.  I have attempted to be
+     accurate with the details.  everything is now under Tatu's licence
+     (which I copied from his readme), and/or the core-sdi bsd-ish thing
+     for deattack, or various openbsd developers under a 2-term bsd
+     licence.  We're not changing any rules, just being accurate.
+   - markus@cvs.openbsd.org  2000/09/07 14:40:30
+     [channels.c channels.h clientloop.c serverloop.c ssh.c]
+     cleanup window and packet sizes for ssh2 flow control; ok niels
+   - markus@cvs.openbsd.org  2000/09/07 14:53:00
+     [scp.c]
+     typo
+   - markus@cvs.openbsd.org  2000/09/07 15:13:37
+     [auth-options.c auth-options.h auth-rh-rsa.c auth-rsa.c auth.c]
+     [authfile.h canohost.c channels.h compat.c hostfile.h log.c match.h]
+     [pty.c readconf.c]
+     some more Copyright fixes
+   - markus@cvs.openbsd.org  2000/09/08 03:02:51
+     [README.openssh2]
+     bye bye
+   - deraadt@cvs.openbsd.org 2000/09/11 18:38:33
+     [LICENCE cipher.c]
+     a few more comments about it being ARC4 not RC4
+   - markus@cvs.openbsd.org  2000/09/12 14:53:11
+     [log-client.c log-server.c log.c ssh.1 ssh.c ssh.h sshd.8 sshd.c]
+     multiple debug levels
+   - markus@cvs.openbsd.org  2000/09/14 14:25:15
+     [clientloop.c]
+     typo
+   - deraadt@cvs.openbsd.org 2000/09/15 01:13:51
+     [ssh-agent.c]
+     check return value for setenv(3) for failure, and deal appropriately
+
+20000913
+ - (djm) Fix server not exiting with jobs in background.
+
+20000905
+ - (djm) Import OpenBSD CVS changes
+   - markus@cvs.openbsd.org  2000/08/31 15:52:24
+     [Makefile sshd.8 sshd_config sftp-server.8 sftp-server.c]
+     implement a SFTP server. interops with sftp2, scp2 and the windows
+     client from ssh.com
+   - markus@cvs.openbsd.org  2000/08/31 15:56:03
+     [README.openssh2]
+     sync
+   - markus@cvs.openbsd.org  2000/08/31 16:05:42
+     [session.c]
+     Wall
+   - markus@cvs.openbsd.org  2000/08/31 16:09:34
+     [authfd.c ssh-agent.c]
+     add a flag to SSH2_AGENTC_SIGN_REQUEST for future extensions
+   - deraadt@cvs.openbsd.org 2000/09/01 09:25:13
+     [scp.1 scp.c]
+     cleanup and fix -S support; stevesk@sweden.hp.com
+   - markus@cvs.openbsd.org  2000/09/01 16:29:32
+     [sftp-server.c]
+     portability fixes
+   - markus@cvs.openbsd.org  2000/09/01 16:32:41
+     [sftp-server.c]
+     fix cast; mouring@pconline.com
+   - itojun@cvs.openbsd.org  2000/09/03 09:23:28
+     [ssh-add.1 ssh.1]
+     add missing .El against .Bl.
+   - markus@cvs.openbsd.org  2000/09/04 13:03:41
+     [session.c]
+     missing close; ok theo
+   - markus@cvs.openbsd.org  2000/09/04 13:07:21
+     [session.c]
+     fix get_last_login_time order; from andre@van-veen.de
+   - markus@cvs.openbsd.org  2000/09/04 13:10:09
+     [sftp-server.c]
+     more cast fixes; from mouring@pconline.com
+   - markus@cvs.openbsd.org  2000/09/04 13:06:04
+     [session.c]
+     set SSH_ORIGINAL_COMMAND; from Leakin@dfw.nostrum.com, bet@rahul.net
+ - (djm) Cleanup after import. Fix sftp-server compilation, Makefile
+ - (djm) Merge cygwin support from Corinna Vinschen <vinschen@cygnus.com>
+
+20000903
+ - (djm) Fix Redhat init script
+
+20000901
+ - (djm) Pick up Jim's new X11-askpass
+ - (djm) Release 2.2.0p1
+
+20000831
+ - (djm) Workaround SIGPIPE problems on SCO. Fix from Aran Cox
+   <acox@cv.telegroup.com>
+ - (djm) Pick up new version (2.2.0) from OpenBSD CVS
+
+20000830
+ - (djm) Compile warning fixes from Mark Miller <markm@swoon.net>
+ - (djm) Periodically rekey arc4random
+ - (djm) Clean up diff against OpenBSD.
+ - (djm) HPUX 11 needs USE_PIPES as well: Kevin Steves
+   <stevesk@sweden.hp.com>
+ - (djm) Quieten the pam delete credentials error message
+ - (djm) Fix printing of $DISPLAY hack if set by system type. Report from
+   Kevin Steves <stevesk@sweden.hp.com>
+ - (djm) NeXT patch from Ben Lindstrom <mouring@pconline.com>
+ - (djm) Fix doh in bsd-arc4random.c
+
+20000829
+ - (djm) Fix ^C ignored issue on Solaris. Diagnosis from Gert
+   Doering <gert@greenie.muc.de>, John Horne <J.Horne@plymouth.ac.uk> and
+   Garrick James <garrick@james.net>
+ - (djm) Check for SCO pty naming style (ptyp%d/ttyp%d). Based on fix from
+   Bastian Trompetter <btrompetter@firemail.de>
+ - (djm) NeXT tweaks from Ben Lindstrom <mouring@pconline.com>
+ - More OpenBSD updates:
+   - deraadt@cvs.openbsd.org 2000/08/24 15:46:59
+     [scp.c]
+     off_t in sink, to fix files > 2GB, i think, test is still running ;-)
+   - deraadt@cvs.openbsd.org 2000/08/25 10:10:06
+     [session.c]
+     Wall
+   - markus@cvs.openbsd.org  2000/08/26 04:33:43
+     [compat.c]
+     ssh.com-2.3.0
+   - markus@cvs.openbsd.org  2000/08/27 12:18:05
+     [compat.c]
+     compatibility with future ssh.com versions
+   - deraadt@cvs.openbsd.org 2000/08/27 21:50:55
+     [auth-krb4.c session.c ssh-add.c sshconnect.c uidswap.c]
+     print uid/gid as unsigned
+   - markus@cvs.openbsd.org  2000/08/28 13:51:00
+     [ssh.c]
+     enable -n and -f for ssh2
+   - markus@cvs.openbsd.org  2000/08/28 14:19:53
+     [ssh.c]
+     allow combination of -N and -f
+   - markus@cvs.openbsd.org  2000/08/28 14:20:56
+     [util.c]
+     util.c
+   - markus@cvs.openbsd.org  2000/08/28 14:22:02
+     [util.c]
+     undo
+   - markus@cvs.openbsd.org  2000/08/28 14:23:38
+     [util.c]
+     don't complain if setting NONBLOCK fails with ENODEV
+
+20000823
+ - (djm) Define USE_PIPES to avoid socketpair problems on HPUX 10 and SunOS 4
+   Avoids "scp never exits" problem. Reports from Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE> and Tamito KAJIYAMA
+   <kajiyama@grad.sccs.chukyo-u.ac.jp>
+ - (djm) Pick up LOGIN_PROGRAM from environment or PATH if not set by headers
+ - (djm) Add local version to version.h
+ - (djm) Don't reseed arc4random everytime it is used
+ - (djm) OpenBSD CVS updates:
+   - deraadt@cvs.openbsd.org 2000/08/18 20:07:23
+     [ssh.c]
+     accept remsh as a valid name as well; roman@buildpoint.com
+   - deraadt@cvs.openbsd.org 2000/08/18 20:17:13
+     [deattack.c crc32.c packet.c]
+     rename crc32() to ssh_crc32() to avoid zlib name clash.  do not move to
+     libz crc32 function yet, because it has ugly "long"'s in it;
+     oneill@cs.sfu.ca
+   - deraadt@cvs.openbsd.org 2000/08/18 20:26:08
+     [scp.1 scp.c]
+     -S prog support; tv@debian.org
+   - deraadt@cvs.openbsd.org 2000/08/18 20:50:07
+     [scp.c]
+     knf
+   - deraadt@cvs.openbsd.org 2000/08/18 20:57:33
+     [log-client.c]
+     shorten
+   - markus@cvs.openbsd.org  2000/08/19 12:48:11
+     [channels.c channels.h clientloop.c ssh.c ssh.h]
+     support for ~. in ssh2
+   - deraadt@cvs.openbsd.org 2000/08/19 15:29:40
+     [crc32.h]
+     proper prototype
+   - markus@cvs.openbsd.org  2000/08/19 15:34:44
+     [authfd.c authfd.h key.c key.h ssh-add.1 ssh-add.c ssh-agent.1]
+     [ssh-agent.c ssh-keygen.c sshconnect1.c sshconnect2.c Makefile]
+     [fingerprint.c fingerprint.h]
+     add SSH2/DSA support to the agent and some other DSA related cleanups.
+     (note that we cannot talk to ssh.com's ssh2 agents)
+   - markus@cvs.openbsd.org  2000/08/19 15:55:52
+     [channels.c channels.h clientloop.c]
+     more ~ support for ssh2
+   - markus@cvs.openbsd.org  2000/08/19 16:21:19
+     [clientloop.c]
+     oops
+   - millert@cvs.openbsd.org 2000/08/20 12:25:53
+     [session.c]
+     We have to stash the result of get_remote_name_or_ip() before we
+     close our socket or getpeername() will get EBADF and the process
+     will exit.  Only a problem for "UseLogin yes".
+   - millert@cvs.openbsd.org 2000/08/20 12:30:59
+     [session.c]
+     Only check /etc/nologin if "UseLogin no" since login(1) may have its
+     own policy on determining who is allowed to login when /etc/nologin
+     is present.  Also use the _PATH_NOLOGIN define.
+   - millert@cvs.openbsd.org 2000/08/20 12:42:43
+     [auth1.c auth2.c session.c ssh.c]
+     Add calls to setusercontext() and login_get*().  We basically call
+     setusercontext() in most places where previously we did a setlogin().
+     Add default login.conf file and put root in the "daemon" login class.
+   - millert@cvs.openbsd.org 2000/08/21 10:23:31
+     [session.c]
+     Fix incorrect PATH setting; noted by Markus.
+
+20000818
+ - (djm) OpenBSD CVS changes:
+   - markus@cvs.openbsd.org  2000/07/22 03:14:37
+     [servconf.c servconf.h sshd.8 sshd.c sshd_config]
+     random early drop; ok theo, niels
+   - deraadt@cvs.openbsd.org 2000/07/26 11:46:51
+     [ssh.1]
+     typo
+   - deraadt@cvs.openbsd.org 2000/08/01 11:46:11
+     [sshd.8]
+     many fixes from pepper@mail.reppep.com
+   - provos@cvs.openbsd.org  2000/08/01 13:01:42
+     [Makefile.in util.c aux.c]
+     rename aux.c to util.c to help with cygwin port
+   - deraadt@cvs.openbsd.org 2000/08/02 00:23:31
+     [authfd.c]
+     correct sun_len; Alexander@Leidinger.net
+   - provos@cvs.openbsd.org  2000/08/02 10:27:17
+     [readconf.c sshd.8]
+     disable kerberos authentication by default
+   - provos@cvs.openbsd.org  2000/08/02 11:27:05
+     [sshd.8 readconf.c auth-krb4.c]
+     disallow kerberos authentication if we can't verify the TGT; from
+     dugsong@
+     kerberos authentication is on by default only if you have a srvtab.
+   - markus@cvs.openbsd.org  2000/08/04 14:30:07
+     [auth.c]
+     unused
+   - markus@cvs.openbsd.org  2000/08/04 14:30:35
+     [sshd_config]
+     MaxStartups
+   - markus@cvs.openbsd.org  2000/08/15 13:20:46
+     [authfd.c]
+     cleanup; ok niels@
+   - markus@cvs.openbsd.org  2000/08/17 14:05:10
+     [session.c]
+     cleanup login(1)-like jobs, no duplicate utmp entries
+   - markus@cvs.openbsd.org  2000/08/17 14:06:34
+     [session.c sshd.8 sshd.c]
+      sshd -u len, similar to telnetd
+ - (djm) Lastlog was not getting closed after writing login entry
+ - (djm) Add Solaris package support from Rip Loomis <loomisg@cist.saic.com>
+
+20000816
+ - (djm) Replacement for inet_ntoa for Irix (which breaks on gcc)
+ - (djm) Fix strerror replacement for old SunOS. Based on patch from
+   Charles Levert <charles@comm.polymtl.ca>
+ - (djm) Seperate arc4random into seperate file and use OpenSSL's RC4
+   implementation.
+ - (djm) SUN_LEN macro for systems which lack it
+
+20000815
+ - (djm) More SunOS 4.1.x fixes from Nate Itkin <nitkin@europa.com>
+ - (djm) Avoid failures on Irix when ssh is not setuid. Fix from
+   Michael Stone <mstone@cs.loyola.edu>
+ - (djm) Don't seek in directory based lastlogs
+ - (djm) Fix --with-ipaddr-display configure option test. Patch from
+   Jarno Huuskonen <jhuuskon@messi.uku.fi>
+ - (djm) Fix AIX limits from Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+
+20000813
+ - (djm) Add $(srcdir) to includes when compiling (for VPATH). Report from
+   Fabrice bacchella <fabrice.bacchella@marchfirst.fr>
+
+20000809
+ - (djm) Define AIX hard limits if headers don't. Report from
+   Bill Painter <william.t.painter@lmco.com>
+ - (djm) utmp direct write & SunOS 4 patch from Charles Levert
+   <charles@comm.polymtl.ca>
+
+20000808
+ - (djm) Cleanup Redhat RPMs. Generate keys at runtime rather than install
+   time, spec file cleanup.
+
+20000807
+ - (djm) Set 0755 on binaries during install. Report from Lutz Jaenicke
+ - (djm) Suppress error messages on channel close shutdown() failurs
+   works around Linux bug. Patch from Zack Weinberg <zack@wolery.cumb.org>
+ - (djm) Add some more entropy collection commands from Lutz Jaenicke
+
+20000725
+ - (djm) Fix autoconf typo: HAVE_BINRESVPORT_AF -> HAVE_BINDRESVPORT_AF
+
+20000721
+ - (djm) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org  2000/07/16 02:27:22
+     [authfd.c authfd.h channels.c clientloop.c ssh-add.c ssh-agent.c ssh.c]
+     [sshconnect1.c sshconnect2.c]
+     make ssh-add accept dsa keys (the agent does not)
+   - djm@cvs.openbsd.org     2000/07/17 19:25:02
+     [sshd.c]
+     Another closing of stdin; ok deraadt
+   - markus@cvs.openbsd.org  2000/07/19 18:33:12
+     [dsa.c]
+     missing free, reorder
+   - markus@cvs.openbsd.org  2000/07/20 16:23:14
+     [ssh-keygen.1]
+     document input and output files
+
+20000720
+ - (djm) Spec file fix from Petr Novotny <Petr.Novotny@antek.cz>
+
+20000716
+ - (djm) Release 2.1.1p4
+
+20000715
+ - (djm) OpenBSD CVS updates
+   - provos@cvs.openbsd.org  2000/07/13 16:53:22
+     [aux.c readconf.c servconf.c ssh.h]
+     allow multiple whitespace but only one '=' between tokens, bug report from
+     Ralf S. Engelschall <rse@engelschall.com> but different fix. okay deraadt@
+   - provos@cvs.openbsd.org  2000/07/13 17:14:09
+     [clientloop.c]
+     typo; todd@fries.net
+   - provos@cvs.openbsd.org  2000/07/13 17:19:31
+     [scp.c]
+     close can fail on AFS, report error; from Greg Hudson <ghudson@mit.edu>
+   - markus@cvs.openbsd.org  2000/07/14 16:59:46
+     [readconf.c servconf.c]
+     allow leading whitespace. ok niels
+   - djm@cvs.openbsd.org     2000/07/14 22:01:38
+     [ssh-keygen.c ssh.c]
+     Always create ~/.ssh with mode 700; ok Markus
+ - Fixes for SunOS 4.1.4 from Gordon Atwood <gordon@cs.ualberta.ca>
+   - Include floatingpoint.h for entropy.c
+   - strerror replacement
+
+20000712
+ - (djm) Remove -lresolve for Reliant Unix
+ - (djm) OpenBSD CVS Updates:
+   - deraadt@cvs.openbsd.org 2000/07/11 02:11:34
+     [session.c sshd.c ]
+     make MaxStartups code still work with -d; djm
+   - deraadt@cvs.openbsd.org 2000/07/11 13:17:45
+     [readconf.c ssh_config]
+     disable FallBackToRsh by default
+ - (djm) Replace in_addr_t with u_int32_t in bsd-inet_aton.c. Report from
+   Ben Lindstrom <mouring@pconline.com>
+ - (djm) Make building of X11-Askpass and GNOME-Askpass optional in RPM
+   spec file.
+ - (djm) Released 2.1.1p3
+
+20000711
+ - (djm) Fixup for AIX getuserattr() support from Tom Bertelson
+   <tbert@abac.com>
+ - (djm) ReliantUNIX support from Udo Schweigert <ust@cert.siemens.de>
+ - (djm) NeXT: dirent structures to get scp working from Ben Lindstrom
+   <mouring@pconline.com>
+ - (djm) Fix broken inet_ntoa check and ut_user/ut_name confusion, report
+   from Jim Watt <jimw@peisj.pebio.com>
+ - (djm) Replaced bsd-snprintf.c with one from Mutt source tree, it is known
+   to compile on more platforms (incl NeXT).
+ - (djm) Added bsd-inet_aton and configure support for NeXT
+ - (djm) Misc NeXT fixes from Ben Lindstrom <mouring@pconline.com>
+ - (djm) OpenBSD CVS updates:
+   - markus@cvs.openbsd.org  2000/06/26 03:22:29
+     [authfd.c]
+     cleanup, less cut&paste
+   - markus@cvs.openbsd.org  2000/06/26 15:59:19
+     [servconf.c servconf.h session.c sshd.8 sshd.c]
+     MaxStartups: limit number of unauthenticated connections, work by
+     theo and me
+   - deraadt@cvs.openbsd.org 2000/07/05 14:18:07
+     [session.c]
+     use no_x11_forwarding_flag correctly; provos ok
+   - provos@cvs.openbsd.org  2000/07/05 15:35:57
+     [sshd.c]
+     typo
+   - aaron@cvs.openbsd.org   2000/07/05 22:06:58
+     [scp.1 ssh-agent.1 ssh-keygen.1 sshd.8]
+     Insert more missing .El directives. Our troff really should identify
+     these and spit out a warning.
+   - todd@cvs.openbsd.org    2000/07/06 21:55:04
+     [auth-rsa.c auth2.c ssh-keygen.c]
+     clean code is good code
+   - deraadt@cvs.openbsd.org 2000/07/07 02:14:29
+     [serverloop.c]
+     sense of port forwarding flag test was backwards
+   - provos@cvs.openbsd.org  2000/07/08 17:17:31
+     [compat.c readconf.c]
+     replace strtok with strsep; from David Young <dyoung@onthejob.net>
+   - deraadt@cvs.openbsd.org 2000/07/08 19:21:15
+     [auth.h]
+     KNF
+   - ho@cvs.openbsd.org      2000/07/08 19:27:33
+     [compat.c readconf.c]
+     Better conditions for strsep() ending.
+   - ho@cvs.openbsd.org      2000/07/10 10:27:05
+     [readconf.c]
+     Get the correct message on errors. (niels@ ok)
+   - ho@cvs.openbsd.org      2000/07/10 10:30:25
+     [cipher.c kex.c servconf.c]
+     strtok() --> strsep(). (niels@ ok)
+ - (djm) Fix problem with debug mode and MaxStartups
+ - (djm) Don't generate host keys when $(DESTDIR) is set (e.g. during RPM
+   builds)
+ - (djm) Add strsep function from OpenBSD libc for systems that lack it
+
+20000709
+ - (djm) Only enable PAM_TTY kludge for Linux. Problem report from
+   Kevin Steves <stevesk@sweden.hp.com>
+ - (djm) Match prototype and function declaration for rresvport_af.
+   Problem report from Niklas Edmundsson <nikke@ing.umu.se>
+ - (djm) Missing $(DESTDIR) on host-key target causing problems with RPM
+   builds. Problem report from Gregory Leblanc <GLeblanc@cu-portland.edu>
+ - (djm) Replace ut_name with ut_user. Patch from Jim Watt
+   <jimw@peisj.pebio.com>
+ - (djm) Fix pam sprintf fix
+ - (djm) Cleanup entropy collection code a little more. Split initialisation
+   from seeding, perform intialisation immediatly at start, be careful with
+   uids. Based on problem report from Jim Watt <jimw@peisj.pebio.com>
+ - (djm) More NeXT compatibility from Ben Lindstrom <mouring@pconline.com>
+   Including sigaction() et al. replacements
+ - (djm) AIX getuserattr() session initialisation from Tom Bertelson
+   <tbert@abac.com>
+
+20000708
+ - (djm) Fix bad fprintf format handling in auth-pam.c. Patch from
+   Aaron Hopkins <aaron@die.net>
+ - (djm) Fix incorrect configure handling of --with-rsh-path option. Fix from
+   Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - (djm) Fixed undefined variables for OSF SIA. Report from
+   Baars, Henk <Hendrik.Baars@nl.origin-it.com>
+ - (djm) Handle EWOULDBLOCK returns from read() and write() in atomicio.c
+   Fix from Marquess, Steve Mr JMLFDC <Steve.Marquess@DET.AMEDD.ARMY.MIL>
+ - (djm) Don't use inet_addr.
+
+20000702
+ - (djm) Fix brace mismatch from Corinna Vinschen <vinschen@cygnus.com>
+ - (djm) Stop shadow expiry checking from preventing logins with NIS. Based
+   on fix from HARUYAMA Seigo <haruyama@nt.phys.s.u-tokyo.ac.jp>
+ - (djm) Use standard OpenSSL functions in auth-skey.c. Patch from
+   Chris, the Young One <cky@pobox.com>
+ - (djm) Fix scp progress meter on really wide terminals. Based on patch
+   from James H. Cloos Jr. <cloos@jhcloos.com>
+
+20000701
+ - (djm) Fix Tru64 SIA problems reported by John P Speno <speno@isc.upenn.edu>
+ - (djm) Login fixes from Tom Bertelson <tbert@abac.com>
+ - (djm) Replace "/bin/sh" with _PATH_BSHELL. Report from Corinna Vinschen
+   <vinschen@cygnus.com>
+ - (djm) Replace "/usr/bin/login" with LOGIN_PROGRAM
+ - (djm) Added check for broken snprintf() functions which do not correctly
+   terminate output string and attempt to use replacement.
+ - (djm) Released 2.1.1p2
+
+20000628
+ - (djm) Fixes to lastlog code for Irix
+ - (djm) Use atomicio in loginrec
+ - (djm) Patch from Michael Stone <mstone@cs.loyola.edu> to add support for
+   Irix 6.x array sessions, project id's, and system audit trail id.
+ - (djm) Added 'distprep' make target to simplify packaging
+ - (djm) Added patch from Chris Adams <cmadams@hiwaay.net> to add OSF SIA
+   support. Enable using "USE_SIA=1 ./configure [options]"
+
+20000627
+ - (djm) Fixes to login code - not setting li->uid, cleanups
+ - (djm) Formatting
+
+20000626
+ - (djm) Better fix to aclocal tests from Garrick James <garrick@james.net>
+ - (djm) Account expiry support from Andreas Steinmetz <ast@domdv.de>
+ - (djm) Added password expiry checking (no password change support)
+ - (djm) Make EGD failures non-fatal if OpenSSL's entropy pool is still OK
+   based on patch from Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - (djm) Fix fixed EGD code.
+ - OpenBSD CVS update
+   - provos@cvs.openbsd.org  2000/06/25 14:17:58
+     [channels.c]
+     correct check for bad channel ids; from Wei Dai <weidai@eskimo.com>
+
+20000623
+ - (djm) Use sa_family_t in prototype for rresvport_af. Patch from
+   Svante Signell <svante.signell@telia.com>
+ - (djm) Autoconf logic to define sa_family_t if it is missing
+ - OpenBSD CVS Updates:
+   - markus@cvs.openbsd.org  2000/06/22 10:32:27
+     [sshd.c]
+     missing atomicio; report from Steve.Marquess@DET.AMEDD.ARMY.MIL
+   - djm@cvs.openbsd.org     2000/06/22 17:55:00
+     [auth-krb4.c key.c radix.c uuencode.c]
+     Missing CVS idents; ok markus
+
+20000622
+ - (djm) Automatically generate host key during "make install". Suggested
+   by Gary E. Miller <gem@rellim.com>
+ - (djm) Paranoia before kill() system call
+ - OpenBSD CVS Updates:
+   - markus@cvs.openbsd.org  2000/06/18 18:50:11
+     [auth2.c compat.c compat.h sshconnect2.c]
+     make userauth+pubkey interop with ssh.com-2.2.0
+   - markus@cvs.openbsd.org  2000/06/18 20:56:17
+     [dsa.c]
+     mem leak + be more paranoid in dsa_verify.
+   - markus@cvs.openbsd.org  2000/06/18 21:29:50
+     [key.c]
+     cleanup fingerprinting, less hardcoded sizes
+   - markus@cvs.openbsd.org  2000/06/19 19:39:45
+     [atomicio.c auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c]
+     [auth-rsa.c auth-skey.c authfd.c authfd.h authfile.c bufaux.c bufaux.h]
+     [buffer.c buffer.h canohost.c channels.c channels.h cipher.c cipher.h]
+     [clientloop.c compat.c compat.h compress.c compress.h crc32.c crc32.h]
+     [deattack.c dispatch.c dsa.c fingerprint.c fingerprint.h getput.h hmac.c]
+     [kex.c log-client.c log-server.c login.c match.c mpaux.c mpaux.h nchan.c]
+     [nchan.h packet.c packet.h pty.c pty.h readconf.c readconf.h readpass.c]
+     [rsa.c rsa.h scp.c servconf.c servconf.h ssh-add.c ssh-keygen.c ssh.c]
+     [ssh.h tildexpand.c ttymodes.c ttymodes.h uidswap.c xmalloc.c xmalloc.h]
+     OpenBSD tag
+   - markus@cvs.openbsd.org  2000/06/21 10:46:10
+     sshconnect2.c missing free; nuke old comment
+
+20000620
+ - (djm) Replace use of '-o' and '-a' logical operators in configure tests
+   with '||' and '&&'. As suggested by Jim Knoble <jmknoble@jmknoble.cx>
+   to fix SCO Unixware problem reported by Gary E. Miller <gem@rellim.com>
+ - (djm) Typo in loginrec.c
+
+20000618
+ - (djm) Add summary of configure options to end of ./configure run
+ - (djm) Not all systems define RUSAGE_SELF & RUSAGE_CHILDREN. Report from
+   Michael Stone <mstone@cs.loyola.edu>
+ - (djm) rusage is a privileged operation on some Unices (incl.
+   Solaris 2.5.1). Report from Paul D. Smith <pausmith@nortelnetworks.com>
+ - (djm) Avoid PAM failures when running without a TTY. Report from
+   Martin Petrak <petrak@spsknm.schools.sk>
+ - (djm) Include sys/types.h when including netinet/in.h in configure tests.
+   Patch from Jun-ichiro itojun Hagino <itojun@iijlab.net>
+ - (djm) Started merge of Ben Lindstrom's <mouring@pconline.com> NeXT support
+ - OpenBSD CVS updates:
+   - deraadt@cvs.openbsd.org 2000/06/17 09:58:46
+     [channels.c]
+     everyone says "nix it" (remove protocol 2 debugging message)
+   - markus@cvs.openbsd.org  2000/06/17 13:24:34
+     [sshconnect.c]
+     allow extended server banners
+   - markus@cvs.openbsd.org  2000/06/17 14:30:10
+     [sshconnect.c]
+     missing atomicio, typo
+   - jakob@cvs.openbsd.org   2000/06/17 16:52:34
+     [servconf.c servconf.h session.c sshd.8 sshd_config]
+     add support for ssh v2 subsystems. ok markus@.
+   - deraadt@cvs.openbsd.org 2000/06/17 18:57:48
+     [readconf.c servconf.c]
+     include = in WHITESPACE; markus ok
+   - markus@cvs.openbsd.org  2000/06/17 19:09:10
+     [auth2.c]
+     implement bug compatibility with ssh-2.0.13 pubkey, server side
+   - markus@cvs.openbsd.org  2000/06/17 21:00:28
+     [compat.c]
+     initial support for ssh.com's 2.2.0
+   - markus@cvs.openbsd.org  2000/06/17 21:16:09
+     [scp.c]
+     typo
+   - markus@cvs.openbsd.org  2000/06/17 22:05:02
+     [auth-rsa.c auth2.c serverloop.c session.c auth-options.c auth-options.h]
+     split auth-rsa option parsing into auth-options
+     add options support to authorized_keys2
+   - markus@cvs.openbsd.org  2000/06/17 22:42:54
+     [session.c]
+     typo
+
+20000613
+ - (djm) Fixes from Andrew McGill <andrewm@datrix.co.za>:
+  - Platform define for SCO 3.x which breaks on /dev/ptmx
+  - Detect and try to fix missing MAXPATHLEN
+ - (djm) Fix short copy in loginrec.c (based on patch from Phill Camp
+   <P.S.S.Camp@ukc.ac.uk>
+
+20000612
+ - (djm) Glob manpages in RPM spec files to catch compressed files
+ - (djm) Full license in auth-pam.c
+ - (djm) Configure fixes from SAKAI Kiyotaka <ksakai@kso.netwk.ntt-at.co.jp>
+ - (andre) AIX, lastlog, configure fixes from Tom Bertelson <tbert@abac.com>:
+  - Don't try to retrieve lastlog from wtmp/wtmpx if DISABLE_LASTLOG is
+     def'd
+  - Set AIX to use preformatted manpages
+
+20000610
+ - (djm) Minor doc tweaks
+ - (djm) Fix for configure on bash2 from Jim Knoble <jmknoble@jmknoble.cx>
+
+20000609
+ - (djm) Patch from Kenji Miyake <kenji@miyake.org> to disable utmp usage
+   (in favour of utmpx) on Solaris 8
+
+20000606
+ - (djm) Cleanup of entropy.c. Reorganised code, removed second pass through
+   list of commands (by default). Removed verbose debugging (by default).
+ - (djm) Increased command entropy estimates and default entropy collection
+   timeout
+ - (djm) Remove duplicate headers from loginrec.c
+ - (djm) Don't add /usr/local/lib to library search path on Irix
+ - (djm) Fix rsh path in RPMs. Report from Jason L Tibbitts III
+   <tibbs@math.uh.edu>
+ - (djm) Warn user if grabs fail in GNOME askpass. Patch from Zack Weinberg
+   <zack@wolery.cumb.org>
+ - (djm) OpenBSD CVS updates:
+  - todd@cvs.openbsd.org
+    [sshconnect2.c]
+    teach protocol v2 to count login failures properly and also enable an
+    explanation of why the password prompt comes up again like v1; this is NOT
+    crypto
+  - markus@cvs.openbsd.org
+    [readconf.c readconf.h servconf.c servconf.h session.c ssh.1 ssh.c sshd.8]
+    xauth_location support; pr 1234
+    [readconf.c sshconnect2.c]
+    typo, unused
+    [session.c]
+    allow use_login only for login sessions, otherwise remote commands are
+    execed with uid==0
+    [sshd.8]
+    document UseLogin better
+    [version.h]
+    OpenSSH 2.1.1
+    [auth-rsa.c]
+    fix match_hostname() logic for auth-rsa: deny access if we have a
+    negative match or no match at all
+    [channels.c hostfile.c match.c]
+    don't panic if mkdtemp fails for authfwd; jkb@yahoo-inc.com via
+    kris@FreeBSD.org
+
+20000606
+ - (djm) Added --with-cflags, --with-ldflags and --with-libs options to
+   configure.
+
+20000604
+ - Configure tweaking for new login code on Irix 5.3
+ - (andre) login code changes based on djm feedback
+
+20000603
+ - (andre) New login code
+    - Remove bsd-login.[ch] and all the OpenBSD-derived code in login.c
+    - Add loginrec.[ch], logintest.c and autoconf code
+
+20000531
+ - Cleanup of auth.c, login.c and fake-*
+ - Cleanup of auth-pam.c, save and print "account expired" error messages
+ - Fix EGD read bug by IWAMURO Motonori <iwa@mmp.fujitsu.co.jp>
+ - Rewrote bsd-login to use proper utmp API if available. Major cleanup
+   of fallback DIY code.
+
+20000530
+ - Define atexit for old Solaris
+ - Fix buffer overrun in login.c for systems which use syslen in utmpx.
+   patch from YOSHIFUJI Hideaki <yoshfuji@cerberus.nemoto.ecei.tohoku.ac.jp>
+ - OpenBSD CVS updates:
+  - markus@cvs.openbsd.org
+    [session.c]
+    make x11-fwd work w/ localhost (xauth add host/unix:11)
+    [cipher.c compat.c readconf.c servconf.c]
+    check strtok() != NULL; ok niels@
+    [key.c]
+    fix key_read() for uuencoded keys w/o '='
+    [serverloop.c]
+    group ssh1 vs. ssh2 in serverloop
+    [kex.c kex.h myproposal.h sshconnect2.c sshd.c]
+    split kexinit/kexdh, factor out common code
+    [readconf.c ssh.1 ssh.c]
+    forwardagent defaults to no, add ssh -A
+  - theo@cvs.openbsd.org
+    [session.c]
+    just some line shortening
+ - Released 2.1.0p3
+
+20000520
+ - Xauth fix from Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
+ - Don't touch utmp if USE_UTMPX defined
+ - SunOS 4.x support from Todd C. Miller <Todd.Miller@courtesan.com>
+ - SIGCHLD fix for AIX and HPUX from Tom Bertelson <tbert@abac.com>
+ - HPUX and Configure fixes from Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - Use mkinstalldirs script to make directories instead of non-portable
+   "install -d". Suggested by Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - Doc cleanup
+
+20000518
+ - Include Andre Lucas' fixprogs script. Forgot to "cvs add" it yesterday
+ - OpenBSD CVS updates:
+  - markus@cvs.openbsd.org
+    [sshconnect.c]
+    copy only ai_addrlen bytes; misiek@pld.org.pl
+    [auth.c]
+    accept an empty shell in authentication; bug reported by
+    chris@tinker.ucr.edu
+    [serverloop.c]
+    we don't have stderr for interactive terminal sessions (fcntl errors)
+
+20000517
+ - Fix from Andre Lucas <andre.lucas@dial.pipex.com>
+  - Fixes command line printing segfaults (spotter: Bladt Norbert)
+  - Fixes erroneous printing of debug messages to syslog
+  - Fixes utmp for MacOS X (spotter: Aristedes Maniatis)
+  - Gives useful error message if PRNG initialisation fails
+  - Reduced ssh startup delay
+  - Measures cumulative command time rather than the time between reads
+    after select()
+  - 'fixprogs' perl script to eliminate non-working entropy commands, and
+    optionally run 'ent' to measure command entropy
+ - Applied Tom Bertelson's <tbert@abac.com> AIX authentication fix
+ - Avoid WCOREDUMP complation errors for systems that lack it
+ - Avoid SIGCHLD warnings from entropy commands
+ - Fix HAVE_PAM_GETENVLIST setting from Simon Wilkinson <sxw@dcs.ed.ac.uk>
+ - OpenBSD CVS update:
+  - markus@cvs.openbsd.org
+    [ssh.c]
+    fix usage()
+    [ssh2.h]
+    draft-ietf-secsh-architecture-05.txt
+    [ssh.1]
+    document ssh -T -N (ssh2 only)
+    [channels.c serverloop.c ssh.h sshconnect.c sshd.c aux.c]
+    enable nonblocking IO for sshd w/ proto 1, too; split out common code
+    [aux.c]
+    missing include
+ - Several patches from SAKAI Kiyotaka <ksakai@kso.netwk.ntt-at.co.jp>
+  - INSTALL typo and URL fix
+  - Makefile fix
+  - Solaris fixes
+ - Checking for ssize_t and memmove. Based on patch from SAKAI Kiyotaka
+   <ksakai@kso.netwk.ntt-at.co.jp>
+ - RSAless operation patch from kevin_oconnor@standardandpoors.com
+ - Detect OpenSSL seperatly from RSA
+ - Better test for RSA (more compatible with RSAref). Based on work by
+   Ed Eden <ede370@stl.rural.usda.gov>
+
+20000513
+ - Fix for non-recognised DSA keys from Arkadiusz Miskiewicz
+   <misiek@pld.org.pl>
+
+20000511
+ - Fix for prng_seed permissions checking from Lutz Jaenicke
+   <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+ - "make host-key" fix for Irix
+
+20000509
+ - OpenBSD CVS update
+  - markus@cvs.openbsd.org
+    [cipher.h myproposal.h readconf.c readconf.h servconf.c ssh.1 ssh.c]
+    [ssh.h sshconnect1.c sshconnect2.c sshd.8]
+    - complain about invalid ciphers in SSH1 (e.g. arcfour is SSH2 only)
+  - hugh@cvs.openbsd.org
+    [ssh.1]
+    - zap typo
+    [ssh-keygen.1]
+    - One last nit fix. (markus approved)
+    [sshd.8]
+    - some markus certified spelling adjustments
+  - markus@cvs.openbsd.org
+    [auth2.c channels.c clientloop.c compat compat.h dsa.c kex.c]
+    [sshconnect2.c ]
+    - bug compat w/ ssh-2.0.13 x11, split out bugs
+    [nchan.c]
+    - no drain if ibuf_empty, fixes x11fwd problems; tests by fries@
+    [ssh-keygen.c]
+    - handle escapes in real and original key format, ok millert@
+    [version.h]
+    - OpenSSH-2.1
+ - Moved all the bsd-* and fake-* stuff into new libopenbsd-compat.a
+ - Doc updates
+ - Cleanup of bsd-base64 headers, bugfix definitions of __b64_*. Reported
+   by Andre Lucas <andre.lucas@dial.pipex.com>
+
+20000508
+ - Makefile and RPM spec fixes
+ - Generate DSA host keys during "make key" or RPM installs
+ - OpenBSD CVS update
+  - markus@cvs.openbsd.org
+    [clientloop.c sshconnect2.c]
+    - make x11-fwd interop w/ ssh-2.0.13
+    [README.openssh2]
+    - interop w/ SecureFX
+ - Release 2.0.0beta2
+
+ - Configure caching and cleanup patch from Andre Lucas'
+   <andre.lucas@dial.pipex.com>
+
+20000507
+ - Remove references to SSLeay.
+ - Big OpenBSD CVS update
+  - markus@cvs.openbsd.org
+    [clientloop.c]
+    - typo
+    [session.c]
+    - update proctitle on pty alloc/dealloc, e.g. w/ windows client
+    [session.c]
+    - update proctitle for proto 1, too
+    [channels.h nchan.c serverloop.c session.c sshd.c]
+    - use c-style comments
+  - deraadt@cvs.openbsd.org
+    [scp.c]
+    - more atomicio
+  - markus@cvs.openbsd.org
+    [channels.c]
+    - set O_NONBLOCK
+    [ssh.1]
+    - update AUTHOR
+    [readconf.c ssh-keygen.c ssh.h]
+    - default DSA key file ~/.ssh/id_dsa
+    [clientloop.c]
+    - typo, rm verbose debug
+  - deraadt@cvs.openbsd.org
+    [ssh-keygen.1]
+    - document DSA use of ssh-keygen
+    [sshd.8]
+    - a start at describing what i understand of the DSA side
+    [ssh-keygen.1]
+    - document -X and -x
+    [ssh-keygen.c]
+    - simplify usage
+  - markus@cvs.openbsd.org
+    [sshd.8]
+    - there is no rhosts_dsa
+    [ssh-keygen.1]
+    - document -y, update -X,-x
+    [nchan.c]
+    - fix close for non-open ssh1 channels
+    [servconf.c servconf.h ssh.h sshd.8 sshd.c ]
+    - s/DsaKey/HostDSAKey/, document option
+    [sshconnect2.c]
+    - respect number_of_password_prompts
+    [channels.c channels.h servconf.c servconf.h session.c sshd.8]
+    - GatewayPorts for sshd, ok deraadt@
+    [ssh-add.1 ssh-agent.1 ssh.1]
+    - more doc on: DSA, id_dsa, known_hosts2, authorized_keys2
+    [ssh.1]
+    - more info on proto 2
+    [sshd.8]
+    - sync AUTHOR w/ ssh.1
+    [key.c key.h sshconnect.c]
+    - print key type when talking about host keys
+    [packet.c]
+    - clear padding in ssh2
+    [dsa.c key.c radix.c ssh.h sshconnect1.c uuencode.c uuencode.h]
+    - replace broken uuencode w/ libc b64_ntop
+    [auth2.c]
+    - log failure before sending the reply
+    [key.c radix.c uuencode.c]
+    - remote trailing comments before calling __b64_pton
+    [auth2.c readconf.c readconf.h servconf.c servconf.h ssh.1]
+    [sshconnect2.c sshd.8]
+    - add DSAAuthetication option to ssh/sshd, document SSH2 in sshd.8
+ - Bring in b64_ntop and b64_pton from OpenBSD libc (bsd-base64.[ch])
+
+20000502
+ - OpenBSD CVS update
+   [channels.c]
+   - init all fds, close all fds.
+   [sshconnect2.c]
+   - check whether file exists before asking for passphrase
+   [servconf.c servconf.h sshd.8 sshd.c]
+   - PidFile, pr 1210
+   [channels.c]
+   - EINTR
+   [channels.c]
+   - unbreak, ok niels@
+   [sshd.c]
+   - unlink pid file, ok niels@
+   [auth2.c]
+   - Add missing #ifdefs; ok - markus
+ - Add Andre Lucas' <andre.lucas@dial.pipex.com> patch to read entropy
+   gathering commands from a text file
+ - Release 2.0.0beta1
+
+20000501
+ - OpenBSD CVS update
+   [packet.c]
+   - send debug messages in SSH2 format
+   [scp.c]
+   - fix very rare EAGAIN/EINTR issues; based on work by djm
+   [packet.c]
+   - less debug, rm unused
+   [auth2.c]
+   - disable kerb,s/key in ssh2
+   [sshd.8]
+   - Minor tweaks and typo fixes.
+   [ssh-keygen.c]
+   - Put -d into usage and reorder. markus ok.
+ - Include missing headers for OpenSSL tests. Fix from Phil Karn
+   <karn@ka9q.ampr.org>
+ - Fixed __progname symbol collisions reported by Andre Lucas
+   <andre.lucas@dial.pipex.com>
+ - Merged bsd-login ttyslot and AIX utmp patch from Gert Doering
+   <gd@hilb1.medat.de>
+ - Add some missing ifdefs to auth2.c
+ - Deprecate perl-tk askpass.
+ - Irix portability fixes - don't include netinet headers more than once
+ - Make sure we don't save PRNG seed more than once
+
+20000430
+ - Merge HP-UX fixes and TCB support from Ged Lodder <lodder@yacc.com.au>
+ - Integrate Andre Lucas' <andre.lucas@dial.pipex.com> entropy collection
+   patch.
+   - Adds timeout to entropy collection
+   - Disables slow entropy sources
+   - Load and save seed file
+ - Changed entropy seed code to user per-user seeds only (server seed is
+   saved in root's .ssh directory)
+ - Use atexit() and fatal cleanups to save seed on exit
+ - More OpenBSD updates:
+   [session.c]
+   - don't call chan_write_failed() if we are not writing
+   [auth-rsa.c auth1.c authfd.c hostfile.c ssh-agent.c]
+   - keysize warnings error() -> log()
+
+20000429
+ - Merge big update to OpenSSH-2.0 from OpenBSD CVS
+   [README.openssh2]
+   - interop w/ F-secure windows client
+   - sync documentation
+   - ssh_host_dsa_key not ssh_dsa_key
+   [auth-rsa.c]
+   - missing fclose
+   [auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c]
+   [readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c]
+   [sshd.c uuencode.c uuencode.h authfile.h]
+   - add DSA pubkey auth and other SSH2 fixes.  use ssh-keygen -[xX]
+     for trading keys with the real and the original SSH, directly from the
+     people who invented the SSH protocol.
+   [auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h]
+   [sshconnect1.c sshconnect2.c]
+   - split auth/sshconnect in one file per protocol version
+   [sshconnect2.c]
+   - remove debug
+   [uuencode.c]
+   - add trailing =
+   [version.h]
+   - OpenSSH-2.0
+   [ssh-keygen.1 ssh-keygen.c]
+   - add -R flag: exit code indicates if RSA is alive
+   [sshd.c]
+   - remove unused
+     silent if -Q is specified
+   [ssh.h]
+   - host key becomes /etc/ssh_host_dsa_key
+   [readconf.c servconf.c ]
+   - ssh/sshd default to proto 1 and 2
+   [uuencode.c]
+   - remove debug
+   [auth2.c ssh-keygen.c sshconnect2.c sshd.c]
+   - xfree DSA blobs
+   [auth2.c serverloop.c session.c]
+   - cleanup logging for sshd/2, respect PasswordAuth no
+   [sshconnect2.c]
+   - less debug, respect .ssh/config
+   [README.openssh2 channels.c channels.h]
+   - clientloop.c session.c ssh.c
+   - support for x11-fwding, client+server
+
+20000421
+ - Merge fix from OpenBSD CVS
+  [ssh-agent.c]
+  - Fix memory leak per connection. Report from Andy Spiegl <Andy@Spiegl.de>
+    via Debian bug #59926
+ - Define __progname in session.c if libc doesn't
+ - Remove indentation on autoconf #include statements to avoid bug in
+   DEC Tru64 compiler. Report and fix from David Del Piero
+   <David.DelPiero@qed.qld.gov.au>
+
+20000420
+ - Make fixpaths work with perl4, patch from Andre Lucas
+   <andre.lucas@dial.pipex.com>
+ - Sync with OpenBSD CVS:
+  [clientloop.c login.c serverloop.c ssh-agent.c ssh.h sshconnect.c sshd.c]
+  - pid_t
+  [session.c]
+  - remove bogus chan_read_failed. this could cause data
+    corruption (missing data) at end of a SSH2 session.
+ - Merge fixes from Debian patch from Phil Hands <phil@hands.com>
+  - Allow setting of PAM service name through CFLAGS (SSHD_PAM_SERVICE)
+  - Use vhangup to clean up Linux ttys
+  - Force posix getopt processing on GNU libc systems
+ - Debian bug #55910 - remove references to ssl(8) manpages
+ - Debian bug #58031 - ssh_config lies about default cipher
+
+20000419
+ - OpenBSD CVS updates
+   [channels.c]
+   - fix pr 1196, listen_port and port_to_connect interchanged
+   [scp.c]
+   - after completion, replace the progress bar ETA counter with a final
+     elapsed time; my idea, aaron wrote the patch
+   [ssh_config sshd_config]
+   - show 'Protocol' as an example, ok markus@
+   [sshd.c]
+   - missing xfree()
+ - Add missing header to bsd-misc.c
+
+20000416
+ - Reduce diff against OpenBSD source
+   - All OpenSSL includes are now unconditionally referenced as
+     openssl/foo.h
+   - Pick up formatting changes
+   - Other minor changed (typecasts, etc) that I missed
+
+20000415
+ - OpenBSD CVS updates.
+   [ssh.1 ssh.c]
+   - ssh -2
+   [auth.c channels.c clientloop.c packet.c packet.h serverloop.c]
+   [session.c sshconnect.c]
+   - check payload for (illegal) extra data
+   [ALL]
+   whitespace cleanup
+
+20000413
+ - INSTALL doc updates
+ - Merged OpenBSD updates to include paths.
+
+20000412
+ - OpenBSD CVS updates:
+   - [channels.c]
+     repair x11-fwd
+   - [sshconnect.c]
+     fix passwd prompt for ssh2, less debugging output.
+   - [clientloop.c compat.c dsa.c kex.c sshd.c]
+     less debugging output
+   - [kex.c kex.h sshconnect.c sshd.c]
+     check for reasonable public DH values
+   - [README.openssh2 cipher.c cipher.h compat.c compat.h readconf.c]
+     [readconf.h servconf.c servconf.h ssh.c ssh.h sshconnect.c sshd.c]
+     add Cipher and Protocol options to ssh/sshd, e.g.:
+     ssh -o 'Protocol 1,2' if you prefer proto 1, ssh -o 'Ciphers
+     arcfour,3des-cbc'
+   - [sshd.c]
+     print 1.99 only if server supports both
+
+20000408
+ - Avoid some compiler warnings in fake-get*.c
+ - Add IPTOS macros for systems which lack them
+ - Only set define entropy collection macros if they are found
+ - More large OpenBSD CVS updates:
+   - [auth.c auth.h servconf.c servconf.h serverloop.c session.c]
+     [session.h ssh.h sshd.c README.openssh2]
+     ssh2 server side, see README.openssh2; enable with 'sshd -2'
+   - [channels.c]
+     no adjust after close
+   - [sshd.c compat.c ]
+     interop w/ latest ssh.com windows client.
+
+20000406
+ - OpenBSD CVS update:
+   - [channels.c]
+     close efd on eof
+   - [clientloop.c compat.c ssh.c sshconnect.c myproposal.h]
+     ssh2 client implementation, interops w/ ssh.com and lsh servers.
+   - [sshconnect.c]
+     missing free.
+   - [authfile.c cipher.c cipher.h packet.c sshconnect.c sshd.c]
+     remove unused argument, split cipher_mask()
+   - [clientloop.c]
+     re-order: group ssh1 vs. ssh2
+ - Make Redhat spec require openssl >= 0.9.5a
+
+20000404
+ - Add tests for RAND_add function when searching for OpenSSL
+ - OpenBSD CVS update:
+   - [packet.h packet.c]
+     ssh2 packet format
+   - [packet.h packet.c nchan2.ms nchan.h compat.h compat.c]
+     [channels.h channels.c]
+     channel layer support for ssh2
+   - [kex.h kex.c hmac.h hmac.c dsa.c dsa.h]
+     DSA, keyexchange, algorithm agreement for ssh2
+ - Generate manpages before make install not at the end of make all
+ - Don't seed the rng quite so often
+ - Always reseed rng when requested
+
+20000403
+ - Wrote entropy collection routines for systems that lack /dev/random
+   and EGD
+ - Disable tests and typedefs for 64 bit types. They are currently unused.
+
+20000401
+ - Big OpenBSD CVS update (mainly beginnings of SSH2 infrastructure)
+   - [auth.c session.c sshd.c auth.h]
+     split sshd.c -> auth.c session.c sshd.c plus cleanup and goto-removal
+   - [bufaux.c bufaux.h]
+     support ssh2 bignums
+   - [channels.c channels.h clientloop.c sshd.c nchan.c nchan.h packet.c]
+     [readconf.c ssh.c ssh.h serverloop.c]
+     replace big switch() with function tables (prepare for ssh2)
+   - [ssh2.h]
+     ssh2 message type codes
+   - [sshd.8]
+     reorder Xr to avoid cutting
+   - [serverloop.c]
+     close(fdin) if fdin != fdout, shutdown otherwise, ok theo@
+   - [channels.c]
+     missing close
+     allow bigger packets
+   - [cipher.c cipher.h]
+     support ssh2 ciphers
+   - [compress.c]
+     cleanup, less code
+   - [dispatch.c dispatch.h]
+     function tables for different message types
+   - [log-server.c]
+     do not log() if debuggin to stderr
+     rename a cpp symbol, to avoid param.h collision
+   - [mpaux.c]
+     KNF
+   - [nchan.c]
+     sync w/ channels.c
+
+20000326
+ - Better tests for OpenSSL w/ RSAref
+ - Added replacement setenv() function from OpenBSD libc. Suggested by
+   Ben Lindstrom <mouring@pconline.com>
+ - OpenBSD CVS update
+   - [auth-krb4.c]
+     -Wall
+   - [auth-rh-rsa.c auth-rsa.c hostfile.c hostfile.h key.c key.h match.c]
+     [match.h ssh.c ssh.h sshconnect.c sshd.c]
+     initial support for DSA keys. ok deraadt@, niels@
+   - [cipher.c cipher.h]
+     remove unused cipher_attack_detected code
+   - [scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8]
+     Fix some formatting problems I missed before.
+   - [ssh.1 sshd.8]
+     fix spelling errors, From: FreeBSD
+   - [ssh.c]
+     switch to raw mode only if he _get_ a pty (not if we _want_ a pty).
+
+20000324
+ - Released 1.2.3
+
+20000317
+ - Clarified --with-default-path option.
+ - Added -blibpath handling for AIX to work around stupid runtime linking.
+   Problem elucidated by gshapiro@SENDMAIL.ORG by way of Jim Knoble
+   <jmknoble@jmknoble.cx>
+ - Checks for 64 bit int types. Problem report from Mats Fredholm
+   <matsf@init.se>
+ - OpenBSD CVS updates:
+   - [atomicio.c auth-krb4.c bufaux.c channels.c compress.c fingerprint.c]
+     [packet.h radix.c rsa.c scp.c ssh-agent.c ssh-keygen.c sshconnect.c]
+     [sshd.c]
+     pedantic: signed vs. unsigned, void*-arithm, etc
+   - [ssh.1 sshd.8]
+     Various cleanups and standardizations.
+ - Runtime error fix for HPUX from Otmar Stahl
+   <O.Stahl@lsw.uni-heidelberg.de>
+
+20000316
+ - Fixed configure not passing LDFLAGS to Solaris. Report from David G.
+   Hesprich <dghespri@sprintparanet.com>
+ - Propogate LD through to Makefile
+ - Doc cleanups
+ - Added blurb about "scp: command not found" errors to UPGRADING
+
+20000315
+ - Fix broken CFLAGS handling during search for OpenSSL. Fixes va_list
+   problems with gcc/Solaris.
+ - Don't free argument to putenv() after use (in setenv() replacement).
+   Report from Seigo Tanimura <tanimura@r.dl.itc.u-tokyo.ac.jp>
+ - Created contrib/ subdirectory. Included helpers from Phil Hands'
+   Debian package, README file and chroot patch from Ricardo Cerqueira
+   <rmcc@clix.pt>
+ - Moved gnome-ssh-askpass.c to contrib directory and removed config
+   option.
+ - Slight cleanup to doc files
+ - Configure fix from Bratislav ILICH <bilic@zepter.ru>
+
+20000314
+ - Include macro for IN6_IS_ADDR_V4MAPPED. Report from
+   peter@frontierflying.com
+ - Include /usr/local/include and /usr/local/lib for systems that don't
+   do it themselves
+ - -R/usr/local/lib for Solaris
+ - Fix RSAref detection
+ - Fix IN6_IS_ADDR_V4MAPPED macro
+
+20000311
+ - Detect RSAref
+ - OpenBSD CVS change
+   [sshd.c]
+    - disallow guessing of root password
+ - More configure fixes
+ - IPv6 workarounds from Hideaki YOSHIFUJI <yoshfuji@ecei.tohoku.ac.jp>
+
+20000309
+ - OpenBSD CVS updates to v1.2.3
+   [ssh.h atomicio.c]
+    - int atomicio -> ssize_t (for alpha). ok deraadt@
+   [auth-rsa.c]
+    - delay MD5 computation until client sends response, free() early, cleanup.
+   [cipher.c]
+    - void* -> unsigned char*, ok niels@
+   [hostfile.c]
+    - remove unused variable 'len'. fix comments.
+    - remove unused variable
+   [log-client.c log-server.c]
+    - rename a cpp symbol, to avoid param.h collision
+   [packet.c]
+    - missing xfree()
+    - getsockname() requires initialized tolen; andy@guildsoftware.com
+    - use getpeername() in packet_connection_is_on_socket(), fixes sshd -i;
+   from Holger.Trapp@Informatik.TU-Chemnitz.DE
+   [pty.c pty.h]
+    - register cleanup for pty earlier. move code for pty-owner handling to
+      pty.c ok provos@, dugsong@
+   [readconf.c]
+    - turn off x11-fwd for the client, too.
+   [rsa.c]
+    - PKCS#1 padding
+   [scp.c]
+    - allow '.' in usernames; from jedgar@fxp.org
+   [servconf.c]
+    - typo: ignore_user_known_hosts int->flag; naddy@mips.rhein-neckar.de
+    - sync with sshd_config
+   [ssh-keygen.c]
+    - enable ssh-keygen -l -f ~/.ssh/known_hosts, ok deraadt@
+   [ssh.1]
+    - Change invalid 'CHAT' loglevel to 'VERBOSE'
+   [ssh.c]
+    - suppress AAAA query host when '-4' is used; from shin@nd.net.fujitsu.co.jp
+    - turn off x11-fwd for the client, too.
+   [sshconnect.c]
+    - missing xfree()
+    - retry rresvport_af(), too. from sumikawa@ebina.hitachi.co.jp.
+    - read error vs. "Connection closed by remote host"
+   [sshd.8]
+    - ie. -> i.e.,
+    - do not link to a commercial page..
+    - sync with sshd_config
+   [sshd.c]
+    - no need for poll.h; from bright@wintelcom.net
+    - log with level log() not fatal() if peer behaves badly.
+    - don't panic if client behaves strange. ok deraadt@
+    - make no-port-forwarding for RSA keys deny both -L and -R style fwding
+    - delay close() of pty until the pty has been chowned back to root
+    - oops, fix comment, too.
+    - missing xfree()
+    - move XAUTHORITY to subdir. ok dugsong@. fixes debian bug #57907, too.
+      (http://cgi.debian.org/cgi-bin/bugreport.cgi?archive=no&bug=57907)
+    - register cleanup for pty earlier. move code for pty-owner handling to
+      pty.c ok provos@, dugsong@
+    - create x11 cookie file
+    - fix pr 1113, fclose() -> pclose(), todo: remote popen()
+    - version 1.2.3
+ - Cleaned up
+ - Removed warning workaround for Linux and devpts filesystems (no longer
+   required after OpenBSD updates)
+
+20000308
+ - Configure fix from Hiroshi Takekawa <takekawa@sr3.t.u-tokyo.ac.jp>
+
+20000307
+ - Released 1.2.2p1
+
+20000305
+ - Fix DEC compile fix
+ - Explicitly seed OpenSSL's PRNG before checking rsa_alive()
+ - Check for getpagesize in libucb.a if not found in libc. Fix for old
+   Solaris from Andre Lucas <andre.lucas@dial.pipex.com>
+ - Check for libwrap if --with-tcp-wrappers option specified. Suggestion
+   Mate Wierdl <mw@moni.msci.memphis.edu>
+
+20000303
+ - Added "make host-key" target, Suggestion from Dominik Brettnacher
+ <domi@saargate.de>
+ - Don't permanently fail on bind() if getaddrinfo has more choices left for
+   us. Needed to work around messy IPv6 on Linux. Patch from Arkadiusz
+   Miskiewicz <misiek@pld.org.pl>
+ - DEC Unix compile fix from David Del Piero <David.DelPiero@qed.qld.gov.au>
+ - Manpage fix from David Del Piero <David.DelPiero@qed.qld.gov.au>
+
+20000302
+ - Big cleanup of autoconf code
+   - Rearranged to be a little more logical
+   - Added -R option for Solaris
+   - Rewrote OpenSSL detection code. Now uses AC_TRY_RUN with a test program
+     to detect library and header location _and_ ensure library has proper
+     RSA support built in (this is a problem with OpenSSL 0.9.5).
+ - Applied pty cleanup patch from markus.friedl@informatik.uni-erlangen.de
+ - Avoid warning message with Unix98 ptys
+ - Warning was valid - possible race condition on PTYs. Avoided using
+   platform-specific code.
+ - Document some common problems
+ - Allow root access to any key. Patch from
+   markus.friedl@informatik.uni-erlangen.de
+
+20000207
+ - Removed SOCKS code. Will support through a ProxyCommand.
+
+20000203
+ - Fixed SEGVs in authloop, fix from vbzoli@hbrt.hu
+ - Add --with-ssl-dir option
+
+20000202
+ - Fix lastlog code for directory based lastlogs. Fix from Josh Durham
+   <jmd@aoe.vt.edu>
+ - Documentation fixes from HARUYAMA Seigo <haruyama@nt.phys.s.u-tokyo.ac.jp>
+ - Added URLs to Japanese translations of documents by HARUYAMA Seigo
+   <haruyama@nt.phys.s.u-tokyo.ac.jp>
+
+20000201
+ - Use socket pairs by default (instead of pipes). Prevents race condition
+   on several (buggy) OSs. Report and fix from tridge@linuxcare.com
+
+20000127
+ - Seed OpenSSL's random number generator before generating RSA keypairs
+ - Split random collector into seperate file
+ - Compile fix from Andre Lucas <andre.lucas@dial.pipex.com>
+
+20000126
+ - Released 1.2.2 stable
+
+ - NeXT keeps it lastlog in /usr/adm. Report from
+   mouring@newton.pconline.com
+ - Added note in UPGRADING re interop with commercial SSH using idea.
+   Report from Jim Knoble <jmknoble@jmknoble.cx>
+ - Fix linking order for Kerberos/AFS. Fix from Holget Trapp
+   <Holger.Trapp@Informatik.TU-Chemnitz.DE>
+
+20000125
+ - Fix NULL pointer dereference in login.c. Fix from Andre Lucas
+   <andre.lucas@dial.pipex.com>
+ - Reorder PAM initialisation so it does not mess up lastlog. Reported
+   by Andre Lucas <andre.lucas@dial.pipex.com>
+ - Use preformatted manpages on SCO, report from Gary E. Miller
+   <gem@rellim.com>
+ - New URL for x11-ssh-askpass.
+ - Fixpaths was missing /etc/ssh_known_hosts. Report from Jim Knoble
+   <jmknoble@jmknoble.cx>
+ - Added 'DESTDIR' option to Makefile to ease package building. Patch from
+   Jim Knoble <jmknoble@jmknoble.cx>
+ - Updated RPM spec files to use DESTDIR
+
+20000124
+ - Pick up version 1.2.2 from OpenBSD CVS (no changes, just version number
+   increment)
+
+20000123
+ - OpenBSD CVS:
+   - [packet.c]
+     getsockname() requires initialized tolen; andy@guildsoftware.com
+ - AIX patch from Matt Richards <v2matt@btv.ibm.com> and David Rankin
+   <drankin@bohemians.lexington.ky.us>
+ - Fix lastlog support, patch from Andre Lucas <andre.lucas@dial.pipex.com>
+
+20000122
+ - Fix compilation of bsd-snprintf.c on Solaris, fix from Ben Taylor
+   <bent@clark.net>
+ - Merge preformatted manpage patch from Andre Lucas
+   <andre.lucas@dial.pipex.com>
+ - Make IPv4 use the default in RPM packages
+ - Irix uses preformatted manpages
+ - Missing htons() in bsd-bindresvport.c, fix from Holger Trapp
+   <Holger.Trapp@Informatik.TU-Chemnitz.DE>
+ - OpenBSD CVS updates:
+   - [packet.c]
+     use getpeername() in packet_connection_is_on_socket(), fixes sshd -i;
+     from Holger.Trapp@Informatik.TU-Chemnitz.DE
+   - [sshd.c]
+     log with level log() not fatal() if peer behaves badly.
+   - [readpass.c]
+     instead of blocking SIGINT, catch it ourselves, so that we can clean
+     the tty modes up and kill ourselves -- instead of our process group
+     leader (scp, cvs, ...) going away and leaving us in noecho mode.
+     people with cbreak shells never even noticed..
+   - [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8]
+     ie. -> i.e.,
+
+20000120
+ - Don't use getaddrinfo on AIX
+ - Update to latest OpenBSD CVS:
+   - [auth-rsa.c]
+     - fix user/1056, sshd keeps restrictions; dbt@meat.net
+   - [sshconnect.c]
+     - disable agent fwding for proto 1.3, remove abuse of auth-rsa flags.
+     - destroy keys earlier
+     - split key exchange (kex) and user authentication (user-auth),
+       ok: provos@
+   - [sshd.c]
+     - no need for poll.h; from bright@wintelcom.net
+     - disable agent fwding for proto 1.3, remove abuse of auth-rsa flags.
+     - split key exchange (kex) and user authentication (user-auth),
+       ok: provos@
+ - Big manpage and config file cleanup from Andre Lucas
+   <andre.lucas@dial.pipex.com>
+   - Re-added latest (unmodified) OpenBSD manpages
+ - Doc updates
+ - NetBSD patch from David Rankin <drankin@bohemians.lexington.ky.us> and
+   Christos Zoulas <christos@netbsd.org>
+
+20000119
+ - SCO compile fixes from Gary E. Miller <gem@rellim.com>
+ - Compile fix from Darren_Hall@progressive.com
+ - Linux/glibc-2.1.2 takes a *long* time to look up names for AF_UNSPEC
+   addresses using getaddrinfo(). Added a configure switch to make the
+   default lookup mode AF_INET
+
+20000118
+ - Fixed --with-pid-dir option
+ - Makefile fix from Gary E. Miller <gem@rellim.com>
+ - Compile fix for HPUX and Solaris from Andre Lucas
+   <andre.lucas@dial.pipex.com>
+
+20000117
+ - Clean up bsd-bindresvport.c. Use arc4random() for picking initial
+   port, ignore EINVAL errors (Linux) when searching for free port.
+ - Revert __snprintf -> snprintf aliasing. Apparently Solaris
+   __snprintf isn't. Report from Theo de Raadt <theo@cvs.openbsd.org>
+ - Document location of Redhat PAM file in INSTALL.
+ - Fixed X11 forwarding bug on Linux. libc advertises AF_INET6
+   INADDR_ANY_INIT addresses via getaddrinfo, but may not be able to
+   deliver (no IPv6 kernel support)
+ - Released 1.2.1pre27
+
+ - Fix rresvport_af failure errors (logic error in bsd-bindresvport.c)
+ - Fix --with-ipaddr-display option test. Fix from Jarno Huuskonen
+   <jhuuskon@hytti.uku.fi>
+ - Fix hang on logout if processes are still using the pty. Needs
+   further testing.
+ - Patch from Christos Zoulas <christos@zoulas.com>
+   - Try $prefix first when looking for OpenSSL.
+   - Include sys/types.h when including sys/socket.h in test programs
+ - Substitute PID directory in sshd.8. Suggestion from Andrew
+   Stribblehill <a.d.stribblehill@durham.ac.uk>
+
+20000116
+ - Renamed --with-xauth-path to --with-xauth
+ - Added --with-pid-dir option
+ - Released 1.2.1pre26
+
+ - Compilation fix from Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ - Fixed broken bugfix for /dev/ptmx on Linux systems which lack
+   openpty(). Report from Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+
+20000115
+ - Add --with-xauth-path configure directive and explicit test for
+   /usr/openwin/bin/xauth for Solaris systems. Report from Anders
+   Nordby <anders@fix.no>
+ - Fix incorrect detection of /dev/ptmx on Linux systems that lack
+   openpty. Report from John Seifarth <john@waw.be>
+ - Look for intXX_t and u_intXX_t in sys/bitypes.h if they are not in
+   sys/types.h. Fixes problems on SCO, report from Gary E. Miller
+   <gem@rellim.com>
+ - Use __snprintf and __vnsprintf if they are found where snprintf and
+   vnsprintf are lacking. Suggested by Ben Taylor <bent@shell.clark.net>
+   and others.
+
+20000114
+ - Merged OpenBSD IPv6 patch:
+   - [sshd.c sshd.8 sshconnect.c ssh.h ssh.c servconf.h servconf.c scp.1]
+     [scp.c packet.h packet.c login.c log.c canohost.c channels.c]
+     [hostfile.c sshd_config]
+     ipv6 support: mostly gethostbyname->getaddrinfo/getnameinfo, new
+     features: sshd allows multiple ListenAddress and Port options. note
+     that libwrap is not IPv6-ready. (based on patches from
+     fujiwara@rcac.tdi.co.jp)
+   - [ssh.c canohost.c]
+     more hints (hints.ai_socktype=SOCK_STREAM) for getaddrinfo,
+     from itojun@
+   - [channels.c]
+     listen on _all_ interfaces for X11-Fwd (hints.ai_flags = AI_PASSIVE)
+   - [packet.h]
+     allow auth-kerberos for IPv4 only
+   - [scp.1 sshd.8 servconf.h scp.c]
+     document -4, -6, and 'ssh -L 2022/::1/22'
+   - [ssh.c]
+     'ssh @host' is illegal (null user name), from
+     karsten@gedankenpolizei.de
+   - [sshconnect.c]
+     better error message
+   - [sshd.c]
+     allow auth-kerberos for IPv4 only
+ - Big IPv6 merge:
+   - Cleanup overrun in sockaddr copying on RHL 6.1
+   - Replacements for getaddrinfo, getnameinfo, etc based on versions
+     from patch from KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
+   - Replacement for missing structures on systems that lack IPv6
+   - record_login needed to know about AF_INET6 addresses
+   - Borrowed more code from OpenBSD: rresvport_af and requisites
+
+20000110
+ - Fixes to auth-skey to enable it to use the standard OpenSSL libraries
+
+20000107
+ - New config.sub and config.guess to fix problems on SCO. Supplied
+   by Gary E. Miller <gem@rellim.com>
+ - SCO build fix from Gary E. Miller <gem@rellim.com>
+ - Released 1.2.1pre25
+
+20000106
+ - Documentation update & cleanup
+ - Better KrbIV / AFS detection, based on patch from:
+   Holger Trapp <Holger.Trapp@Informatik.TU-Chemnitz.DE>
+
+20000105
+ - Fixed annoying DES corruption problem. libcrypt has been
+   overriding symbols in libcrypto. Removed libcrypt and crypt.h
+   altogether (libcrypto includes its own crypt(1) replacement)
+ - Added platform-specific rules for Irix 6.x. Included warning that
+   they are untested.
+
+20000103
+ - Add explicit make rules for files proccessed by fixpaths.
+ - Fix "make install" in RPM spec files. Report from Tenkou N. Hattori
+   <tnh@kondara.org>
+ - Removed "nullok" directive from default PAM configuration files.
+   Added information on enabling EmptyPasswords on openssh+PAM in
+   UPGRADING file.
+ - OpenBSD CVS updates
+   - [ssh-agent.c]
+     cleanup_exit() for SIGTERM/SIGHUP, too. from fgsch@ and
+     dgaudet@arctic.org
+   - [sshconnect.c]
+     compare correct version for 1.3 compat mode
+
+20000102
+ - Prevent multiple inclusion of config.h and defines.h. Suggested
+   by Andre Lucas <andre.lucas@dial.pipex.com>
+ - Properly clean up on exit of ssh-agent. Patch from Dean Gaudet
+   <dgaudet@arctic.org>
+
+19991231
+ - Fix password support on systems with a mixture of shadowed and
+   non-shadowed passwords (e.g. NIS). Report and fix from
+   HARUYAMA Seigo <haruyama@nt.phys.s.u-tokyo.ac.jp>
+ - Fix broken autoconf typedef detection. Report from Marc G.
+   Fournier <marc.fournier@acadiau.ca>
+ - Fix occasional crash on LinuxPPC. Patch from Franz Sirl
+   <Franz.Sirl-kernel@lauterbach.com>
+ - Prevent typedefs from being compiled more than once. Report from
+   Marc G. Fournier <marc.fournier@acadiau.ca>
+ - Fill in ut_utaddr utmp field. Report from Benjamin Charron
+   <iretd@bigfoot.com>
+ - Really fix broken default path. Fix from Jim Knoble
+   <jmknoble@jmknoble.cx>
+ - Remove test for quad_t. No longer needed.
+ - Released 1.2.1pre24
+
+ - Added support for directory-based lastlogs
+ - Really fix typedefs, patch from Ben Taylor <bent@clark.net>
+
+19991230
+ - OpenBSD CVS updates:
+   - [auth-passwd.c]
+     check for NULL 1st
+ - Removed most of the pam code into its own file auth-pam.[ch]. This
+   cleaned up sshd.c up significantly.
+ - PAM authentication was incorrectly interpreting
+   "PermitRootLogin without-password". Report from Matthias Andree
+   <ma@dt.e-technik.uni-dortmund.de
+ - Several other cleanups
+ - Merged Dante SOCKS support patch from David Rankin
+  <drankin@bohemians.lexington.ky.us>
+ - Updated documentation with ./configure options
+ - Released 1.2.1pre23
+
+19991229
+ - Applied another NetBSD portability patch from David Rankin
+   <drankin@bohemians.lexington.ky.us>
+ - Fix --with-default-path option.
+ - Autodetect perl, patch from David Rankin
+   <drankin@bohemians.lexington.ky.us>
+ - Print whether OpenSSH was compiled with RSARef, patch from
+   Nalin Dahyabhai <nalin@thermo.stat.ncsu.edu>
+ - Calls to pam_setcred, patch from Nalin Dahyabhai
+   <nalin@thermo.stat.ncsu.edu>
+ - Detect missing size_t and typedef it.
+ - Rename helper.[ch] to (more appropriate) bsd-misc.[ch]
+ - Minor Makefile cleaning
+
+19991228
+ - Replacement for getpagesize() for systems which lack it
+ - NetBSD login.c compile fix from David Rankin
+  <drankin@bohemians.lexington.ky.us>
+ - Fully set ut_tv if present in utmp or utmpx
+ - Portability fixes for Irix 5.3 (now compiles OK!)
+ - autoconf and other misc cleanups
+ - Merged AIX patch from Darren Hall <dhall@virage.org>
+ - Cleaned up defines.h
+ - Released 1.2.1pre22
+
+19991227
+ - Automatically correct paths in manpages and configuration files. Patch
+   and script from Andre Lucas <andre.lucas@dial.pipex.com>
+ - Removed credits from README to CREDITS file, updated.
+ - Added --with-default-path to specify custom path for server
+ - Removed #ifdef trickery from acconfig.h into defines.h
+ - PAM bugfix. PermitEmptyPassword was being ignored.
+ - Fixed PAM config files to allow empty passwords if server does.
+ - Explained spurious PAM auth warning workaround in UPGRADING
+ - Use last few chars of tty line as ut_id
+ - New SuSE RPM spec file from Chris Saia <csaia@wtower.com>
+ - OpenBSD CVS updates:
+   - [packet.h auth-rhosts.c]
+     check format string for packet_disconnect and packet_send_debug, too
+   - [channels.c]
+     use packet_get_maxsize for channels. consistence.
+
+19991226
+ - Enabled utmpx support by default for Solaris
+ - Cleanup sshd.c PAM a little more
+ - Revised RPM package to include Jim Knoble's <jmknoble@jmknoble.cx>
+   X11 ssh-askpass program.
+ - Disable logging of PAM success and failures, PAM is verbose enough.
+   Unfortunatly there is currently no way to disable auth failure
+   messages. Mention this in UPGRADING file and sent message to PAM
+   developers
+ - OpenBSD CVS update:
+   - [ssh-keygen.1 ssh.1]
+     remove ref to .ssh/random_seed, mention .ssh/environment in
+     .Sh FILES, too
+ - Released 1.2.1pre21
+ - Fixed implicit '.' in default path, report from Jim Knoble
+   <jmknoble@jmknoble.cx>
+ - Redhat RPM spec fixes from Jim Knoble <jmknoble@jmknoble.cx>
+
+19991225
+ - More fixes from Andre Lucas <andre.lucas@dial.pipex.com>
+ - Cleanup of auth-passwd.c for shadow and MD5 passwords
+ - Cleanup and bugfix of PAM authentication code
+ - Released 1.2.1pre20
+
+ - Merged fixes from Ben Taylor <bent@clark.net>
+ - Fixed configure support for PAM. Reported by Naz <96na@eng.cam.ac.uk>
+ - Disabled logging of PAM password authentication failures when password
+   is empty. (e.g start of authentication loop). Reported by Naz
+   <96na@eng.cam.ac.uk>)
+
+19991223
+ - Merged later HPUX patch from Andre Lucas
+   <andre.lucas@dial.pipex.com>
+ - Above patch included better utmpx support from Ben Taylor
+   <bent@clark.net>
+
+19991222
+ - Fix undefined fd_set type in ssh.h from Povl H. Pedersen
+   <pope@netguide.dk>
+ - Fix login.c breakage on systems which lack ut_host in struct
+   utmp. Reported by Willard Dawson <willard.dawson@sbs.siemens.com>
+
+19991221
+ - Integration of large HPUX patch from Andre Lucas
+   <andre.lucas@dial.pipex.com>. Integrating it had a few other
+   benefits:
+   - Ability to disable shadow passwords at configure time
+   - Ability to disable lastlog support at configure time
+   - Support for IP address in $DISPLAY
+ - OpenBSD CVS update:
+   - [sshconnect.c]
+   say "REMOTE HOST IDENTIFICATION HAS CHANGED"
+ - Fix DISABLE_SHADOW support
+ - Allow MD5 passwords even if shadow passwords are disabled
+ - Release 1.2.1pre19
+
+19991218
+ - Redhat init script patch from Chun-Chung Chen
+   <cjj@u.washington.edu>
+ - Avoid breakage on systems without IPv6 headers
+
+19991216
+ - Makefile changes for Solaris from Peter Kocks
+   <peter.kocks@baygate.com>
+ - Minor updates to docs
+ - Merged OpenBSD CVS changes:
+   - [authfd.c ssh-agent.c]
+     keysize warnings talk about identity files
+   - [packet.c]
+     "Connection closed by x.x.x.x": fatal() -> log()
+ - Correctly handle empty passwords in shadow file. Patch from:
+   "Chris, the Young One" <cky@pobox.com>
+ - Released 1.2.1pre18
+
+19991215
+ - Integrated patchs from Juergen Keil <jk@tools.de>
+   - Avoid void* pointer arithmatic
+   - Use LDFLAGS correctly
+   - Fix SIGIO error in scp
+   - Simplify status line printing in scp
+ - Added better test for inline functions compiler support from
+   Darren_Hall@progressive.com
+
+19991214
+ - OpenBSD CVS Changes
+   - [canohost.c]
+     fix get_remote_port() and friends for sshd -i;
+     Holger.Trapp@Informatik.TU-Chemnitz.DE
+   - [mpaux.c]
+     make code simpler. no need for memcpy. niels@ ok
+   - [pty.c]
+     namebuflen not sizeof namebuflen; bnd@ep-ag.com via djm@mindrot.org
+     fix proto; markus
+   - [ssh.1]
+      typo; mark.baushke@solipsa.com
+   - [channels.c ssh.c ssh.h sshd.c]
+     type conflict for 'extern Type *options' in channels.c; dot@dotat.at
+   - [sshconnect.c]
+     move checking of hostkey into own function.
+   - [version.h]
+     OpenSSH-1.2.1
+ - Clean up broken includes in pty.c
+ - Some older systems don't have poll.h, they use sys/poll.h instead
+ - Doc updates
+
+19991211
+ - Fix compilation on systems with AFS. Reported by
+   aloomis@glue.umd.edu
+ - Fix installation on Solaris. Reported by
+   Gordon Rowell <gordonr@gormand.com.au>
+ - Fix gccisms (__attribute__ and inline). Report by edgy@us.ibm.com,
+   patch from Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
+ - Auto-locate xauth. Patch from David Agraz <dagraz@jahoopa.com>
+ - Compile fix from David Agraz <dagraz@jahoopa.com>
+ - Avoid compiler warning in bsd-snprintf.c
+ - Added pam_limits.so to default PAM config. Suggested by
+   Jim Knoble <jmknoble@jmknoble.cx>
+
+19991209
+ - Import of patch from Ben Taylor <bent@clark.net>:
+   - Improved PAM support
+   - "uninstall" rule for Makefile
+   - utmpx support
+   - Should fix PAM problems on Solaris
+ - OpenBSD CVS updates:
+   - [readpass.c]
+     avoid stdio; based on work by markus, millert, and I
+   - [sshd.c]
+     make sure the client selects a supported cipher
+   - [sshd.c]
+     fix sighup handling.  accept would just restart and daemon handled
+     sighup only after the next connection was accepted. use poll on
+     listen sock now.
+   - [sshd.c]
+     make that a fatal
+ - Applied patch from David Rankin <drankin@bohemians.lexington.ky.us>
+   to fix libwrap support on NetBSD
+ - Released 1.2pre17
+
+19991208
+ - Compile fix for Solaris with /dev/ptmx from
+   David Agraz <dagraz@jahoopa.com>
+
+19991207
+ - sshd Redhat init script patch from Jim Knoble <jmknoble@jmknoble.cx>
+   fixes compatability with 4.x and 5.x
+ - Fixed default SSH_ASKPASS
+ - Fix PAM account and session being called multiple times. Problem
+   reported by Adrian Baugh <adrian@merlin.keble.ox.ac.uk>
+ - Merged more OpenBSD changes:
+   - [atomicio.c authfd.c scp.c serverloop.c ssh.h sshconnect.c sshd.c]
+     move atomicio into it's own file.  wrap all socket write()s which
+     were doing write(sock, buf, len) != len, with atomicio() calls.
+   - [auth-skey.c]
+     fd leak
+   - [authfile.c]
+     properly name fd variable
+   - [channels.c]
+     display great hatred towards strcpy
+   - [pty.c pty.h sshd.c]
+     use openpty() if it exists (it does on BSD4_4)
+   - [tildexpand.c]
+     check for ~ expansion past MAXPATHLEN
+ - Modified helper.c to use new atomicio function.
+ - Reformat Makefile a little
+ - Moved RC4 routines from rc4.[ch] into helper.c
+ - Added autoconf code to detect /dev/ptmx (Solaris) and /dev/ptc (AIX)
+ - Updated SuSE spec from Chris Saia <csaia@wtower.com>
+ - Tweaked Redhat spec
+ - Clean up bad imports of a few files (forgot -kb)
+ - Released 1.2pre16
+
+19991204
+ - Small cleanup of PAM code in sshd.c
+ - Merged OpenBSD CVS changes:
+   - [auth-krb4.c auth-passwd.c auth-skey.c ssh.h]
+     move skey-auth from auth-passwd.c to auth-skey.c, same for krb4
+   - [auth-rsa.c]
+     warn only about mismatch if key is _used_
+     warn about keysize-mismatch with log() not error()
+     channels.c readconf.c readconf.h ssh.c ssh.h sshconnect.c
+     ports are u_short
+   - [hostfile.c]
+     indent, shorter warning
+   - [nchan.c]
+     use error() for internal errors
+   - [packet.c]
+     set loglevel for SSH_MSG_DISCONNECT to log(), not fatal()
+     serverloop.c
+     indent
+   - [ssh-add.1 ssh-add.c ssh.h]
+     document $SSH_ASKPASS, reasonable default
+   - [ssh.1]
+     CheckHostIP is not available for connects via proxy command
+   - [sshconnect.c]
+     typo
+     easier to read client code for passwd and skey auth
+     turn of checkhostip for proxy connects, since we don't know the remote ip
+
+19991126
+ - Add definition for __P()
+ - Added [v]snprintf() replacement for systems that lack it
+
+19991125
+ - More reformatting merged from OpenBSD CVS
+ - Merged OpenBSD CVS changes:
+   - [channels.c]
+     fix packet_integrity_check() for !have_hostname_in_open.
+     report from mrwizard@psu.edu via djm@ibs.com.au
+   - [channels.c]
+     set SO_REUSEADDR and SO_LINGER for forwarded ports.
+     chip@valinux.com via damien@ibs.com.au
+   - [nchan.c]
+     it's not an error() if shutdown_write failes in nchan.
+   - [readconf.c]
+     remove dead #ifdef-0-code
+   - [readconf.c servconf.c]
+     strcasecmp instead of tolower
+   - [scp.c]
+     progress meter overflow fix from damien@ibs.com.au
+   - [ssh-add.1 ssh-add.c]
+     SSH_ASKPASS support
+   - [ssh.1 ssh.c]
+     postpone fork_after_authentication until command execution,
+     request/patch from jahakala@cc.jyu.fi via damien@ibs.com.au
+     plus: use daemon() for backgrounding
+ - Added BSD compatible install program and autoconf test, thanks to
+   Niels Kristian Bech Jensen <nkbj@image.dk>
+ - Solaris fixing, thanks to Ben Taylor <bent@clark.net>
+ - Merged beginnings of AIX support from Tor-Ake Fransson <torake@hotmail.com>
+ - Release 1.2pre15
+
+19991124
+ - Merged very large OpenBSD source code reformat
+ - OpenBSD CVS updates
+   - [channels.c cipher.c compat.c log-client.c scp.c serverloop.c]
+     [ssh.h sshd.8 sshd.c]
+     syslog changes:
+     * Unified Logmessage for all auth-types, for success and for failed
+     * Standard connections get only ONE line in the LOG when level==LOG:
+       Auth-attempts are logged only, if authentication is:
+          a) successfull or
+          b) with passwd or
+          c) we had more than AUTH_FAIL_LOG failues
+     * many log() became verbose()
+     * old behaviour with level=VERBOSE
+   - [readconf.c readconf.h ssh.1 ssh.h sshconnect.c sshd.c]
+     tranfer s/key challenge/response data in SSH_SMSG_AUTH_TIS_CHALLENGE
+     messages. allows use of s/key in windows (ttssh, securecrt) and
+     ssh-1.2.27 clients without 'ssh -v', ok: niels@
+   - [sshd.8]
+     -V, for fallback to openssh in SSH2 compatibility mode
+   - [sshd.c]
+     fix sigchld race; cjc5@po.cwru.edu
+
+19991123
+ - Added SuSE package files from Chris Saia <csaia@wtower.com>
+ - Restructured package-related files under packages/*
+ - Added generic PAM config
+ - Numerous little Solaris fixes
+ - Add recommendation to use GNU make to INSTALL document
+
+19991122
+ - Make <enter> close gnome-ssh-askpass (Debian bug #50299)
+ - OpenBSD CVS Changes
+   - [ssh-keygen.c]
+     don't create ~/.ssh only if the user wants to store the private
+     key there. show fingerprint instead of public-key after
+     keygeneration. ok niels@
+ - Added OpenBSD bsd-strlcat.c, created bsd-strlcat.h
+ - Added timersub() macro
+ - Tidy RCSIDs of bsd-*.c
+ - Added autoconf test and macro to deal with old PAM libraries
+   pam_strerror definition (one arg vs two).
+ - Fix EGD problems (Thanks to Ben Taylor <bent@clark.net>)
+ - Retry /dev/urandom reads interrupted by signal (report from
+   Robert Hardy <rhardy@webcon.net>)
+ - Added a setenv replacement for systems which lack it
+ - Only display public key comment when presenting ssh-askpass dialog
+ - Released 1.2pre14
+
+ - Configure, Make and changelog corrections from Tudor Bosman
+   <tudorb@jm.nu> and Niels Kristian Bech Jensen <nkbj@image.dk>
+
+19991121
+ - OpenBSD CVS Changes:
+   - [channels.c]
+     make this compile, bad markus
+   - [log.c readconf.c servconf.c ssh.h]
+     bugfix: loglevels are per host in clientconfig,
+     factor out common log-level parsing code.
+   - [servconf.c]
+     remove unused index (-Wall)
+   - [ssh-agent.c]
+     only one 'extern char *__progname'
+   - [sshd.8]
+     document SIGHUP, -Q to synopsis
+   - [sshconnect.c serverloop.c sshd.c packet.c packet.h]
+     [channels.c clientloop.c]
+     SSH_CMSG_MAX_PACKET_SIZE, some clients use this, some need this, niels@
+     [hope this time my ISP stays alive during commit]
+   - [OVERVIEW README] typos; green@freebsd
+   - [ssh-keygen.c]
+     replace xstrdup+strcat with strlcat+fixed buffer, fixes OF (bad me)
+     exit if writing the key fails (no infinit loop)
+     print usage() everytime we get bad options
+   - [ssh-keygen.c] overflow, djm@mindrot.org
+   - [sshd.c] fix sigchld race; cjc5@po.cwru.edu
+
+19991120
+ - Merged more Solaris support from Marc G. Fournier
+   <marc.fournier@acadiau.ca>
+ - Wrote autoconf tests for integer bit-types
+ - Fixed enabling kerberos support
+ - Fix segfault in ssh-keygen caused by buffer overrun in filename
+   handling.
+
+19991119
+ - Merged PAM buffer overrun patch from Chip Salzenberg <chip@valinux.com>
+ - Merged OpenBSD CVS changes
+   - [auth-rhosts.c auth-rsa.c ssh-agent.c sshconnect.c sshd.c]
+     more %d vs. %s in fmt-strings
+   - [authfd.c]
+     Integers should not be printed with %s
+ - EGD uses a socket, not a named pipe. Duh.
+ - Fix includes in fingerprint.c
+ - Fix scp progress bar bug again.
+ - Move ssh-askpass from ${libdir}/ssh to ${libexecdir}/ssh at request of
+   David Rankin <drankin@bohemians.lexington.ky.us>
+ - Added autoconf option to enable Kerberos 4 support (untested)
+ - Added autoconf option to enable AFS support (untested)
+ - Added autoconf option to enable S/Key support (untested)
+ - Added autoconf option to enable TCP wrappers support (compiles OK)
+ - Renamed BSD helper function files to bsd-*
+ - Added tests for login and daemon and enable OpenBSD replacements for
+   when they are absent.
+ - Added non-PAM MD5 password support patch from Tudor Bosman <tudorb@jm.nu>
+
+19991118
+ - Merged OpenBSD CVS changes
+   - [scp.c] foregroundproc() in scp
+   - [sshconnect.h] include fingerprint.h
+   - [sshd.c] bugfix: the log() for passwd-auth escaped during logging
+     changes.
+   - [ssh.1] Spell my name right.
+ - Added openssh.com info to README
+
+19991117
+ - Merged OpenBSD CVS changes
+   - [ChangeLog.Ylonen] noone needs this anymore
+   - [authfd.c] close-on-exec for auth-socket, ok deraadt
+   - [hostfile.c]
+     in known_hosts key lookup the entry for the bits does not need
+     to match, all the information is contained in n and e. This
+     solves the problem with buggy servers announcing the wrong
+     modulus length.  markus and me.
+   - [serverloop.c]
+     bugfix: check for space if child has terminated, from:
+     iedowse@maths.tcd.ie
+   - [ssh-add.1 ssh-add.c ssh-keygen.1 ssh-keygen.c sshconnect.c]
+     [fingerprint.c fingerprint.h]
+     rsa key fingerprints, idea from Bjoern Groenvall <bg@sics.se>
+   - [ssh-agent.1] typo
+   - [ssh.1] add OpenSSH information to AUTHOR section. okay markus@
+   - [sshd.c]
+     force logging to stderr while loading private key file
+     (lost while converting to new log-levels)
+
+19991116
+ - Fix some Linux libc5 problems reported by Miles Wilson <mw@mctitle.com>
+ - Merged OpenBSD CVS changes:
+   - [auth-rh-rsa.c auth-rsa.c authfd.c authfd.h hostfile.c mpaux.c]
+     [mpaux.h ssh-add.c ssh-agent.c ssh.h ssh.c sshd.c]
+     the keysize of rsa-parameter 'n' is passed implizit,
+     a few more checks and warnings about 'pretended' keysizes.
+   - [cipher.c cipher.h packet.c packet.h sshd.c]
+     remove support for cipher RC4
+   - [ssh.c]
+     a note for legay systems about secuity issues with permanently_set_uid(),
+     the private hostkey and ptrace()
+   - [sshconnect.c]
+     more detailed messages about adding and checking hostkeys
+
+19991115
+ - Merged OpenBSD CVS changes:
+   - [ssh-add.c] change passphrase loop logic and remove ref to
+     $DISPLAY, ok niels
+ - Changed to ssh-add.c broke askpass support. Revised it to be a little more
+   modular.
+ - Revised autoconf support for enabling/disabling askpass support.
+ - Merged more OpenBSD CVS changes:
+   [auth-krb4.c]
+     - disconnect if getpeername() fails
+     - missing xfree(*client)
+   [canohost.c]
+     - disconnect if getpeername() fails
+     - fix comment: we _do_ disconnect if ip-options are set
+   [sshd.c]
+     - disconnect if getpeername() fails
+     - move checking of remote port to central place
+   [auth-rhosts.c] move checking of remote port to central place
+   [log-server.c] avoid extra fd per sshd, from millert@
+   [readconf.c] print _all_ bad config-options in ssh(1), too
+   [readconf.h] print _all_ bad config-options in ssh(1), too
+   [ssh.c] print _all_ bad config-options in ssh(1), too
+   [sshconnect.c] disconnect if getpeername() fails
+ - OpenBSD's changes to sshd.c broke the PAM stuff, re-merged it.
+ - Various small cleanups to bring diff (against OpenBSD) size down.
+ - Merged more Solaris compability from Marc G. Fournier
+   <marc.fournier@acadiau.ca>
+ - Wrote autoconf tests for __progname symbol
+ - RPM spec file fixes from Jim Knoble <jmknoble@jmknoble.cx>
+ - Released 1.2pre12
+
+ - Another OpenBSD CVS update:
+   - [ssh-keygen.1] fix .Xr
+
+19991114
+ - Solaris compilation fixes (still imcomplete)
+
+19991113
+ - Build patch from Niels Kristian Bech Jensen <nkbj@image.dk>
+   - Don't install config files if they already exist
+   - Fix inclusion of additional preprocessor directives from acconfig.h
+ - Removed redundant inclusions of config.h
+ - Added 'Obsoletes' lines to RPM spec file
+ - Merged OpenBSD CVS changes:
+   - [bufaux.c] save a view malloc/memcpy/memset/free's, ok niels
+   - [scp.c] fix overflow reported by damien@ibs.com.au: off_t
+     totalsize, ok niels,aaron
+ - Delay fork (-f option) in ssh until after port forwarded connections
+   have been initialised. Patch from Jani Hakala <jahakala@cc.jyu.fi>
+ - Added shadow password patch from Thomas Neumann <tom@smart.ruhr.de>
+ - Added ifdefs to auth-passwd.c to exclude it when PAM is enabled
+ - Tidied default config file some more
+ - Revised Redhat initscript to fix bug: sshd (re)start would fail
+   if executed from inside a ssh login.
+
+19991112
+ - Merged changes from OpenBSD CVS
+   - [sshd.c] session_key_int may be zero
+   - [auth-rh-rsa.c servconf.c servconf.h ssh.h sshd.8 sshd.c sshd_config]
+     IgnoreUserKnownHosts(default=no), used for RhostRSAAuth, ok
+     deraadt,millert
+ - Brought default sshd_config more in line with OpenBSD's
+ - Grab server in gnome-ssh-askpass (Debian bug #49872)
+ - Released 1.2pre10
+
+ - Added INSTALL documentation
+ - Merged yet more changes from OpenBSD CVS
+   - [auth-rh-rsa.c auth-rhosts.c auth-rsa.c channels.c clientloop.c]
+     [ssh.c ssh.h sshconnect.c sshd.c]
+     make all access to options via 'extern Options options'
+     and 'extern ServerOptions options' respectively;
+     options are no longer passed as arguments:
+      * make options handling more consistent
+      * remove #include "readconf.h" from ssh.h
+      * readconf.h is only included if necessary
+   - [mpaux.c] clear temp buffer
+   - [servconf.c] print _all_ bad options found in configfile
+ - Make ssh-askpass support optional through autoconf
+ - Fix nasty division-by-zero error in scp.c
+ - Released 1.2pre11
+
+19991111
+ - Added (untested) Entropy Gathering Daemon (EGD) support
+ - Fixed /dev/urandom fd leak (Debian bug #49722)
+ - Merged OpenBSD CVS changes:
+   - [auth-rh-rsa.c] user/958: check ~/.ssh/known_hosts for rhosts-rsa, too
+   - [ssh.1] user/958: check ~/.ssh/known_hosts for rhosts-rsa, too
+   - [sshd.8] user/958: check ~/.ssh/known_hosts for rhosts-rsa, too
+ - Fix integer overflow which was messing up scp's progress bar for large
+   file transfers. Fix submitted to OpenBSD developers. Report and fix
+   from Kees Cook <cook@cpoint.net>
+ - Merged more OpenBSD CVS changes:
+   - [auth-krb4.c auth-passwd.c] remove x11- and krb-cleanup from fatal()
+     + krb-cleanup cleanup
+   - [clientloop.c log-client.c log-server.c ]
+     [readconf.c readconf.h servconf.c servconf.h ]
+     [ssh.1 ssh.c ssh.h sshd.8]
+     add LogLevel {QUIET, FATAL, ERROR, INFO, CHAT, DEBUG} to ssh/sshd,
+     obsoletes QuietMode and FascistLogging in sshd.
+   - [sshd.c] fix fatal/assert() bug reported by damien@ibs.com.au:
+     allow session_key_int != sizeof(session_key)
+     [this should fix the pre-assert-removal-core-files]
+ - Updated default config file to use new LogLevel option and to improve
+   readability
+
+19991110
+ - Merged several minor fixes:
+   - ssh-agent commandline parsing
+   - RPM spec file now installs ssh setuid root
+   - Makefile creates libdir
+   - Merged beginnings of Solaris compability from Marc G. Fournier
+     <marc.fournier@acadiau.ca>
+
+19991109
+ - Autodetection of SSL/Crypto library location via autoconf
+ - Fixed location of ssh-askpass to follow autoconf
+ - Integrated Makefile patch from Niels Kristian Bech Jensen <nkbj@image.dk>
+ - Autodetection of RSAref library for US users
+ - Minor doc updates
+ - Merged OpenBSD CVS changes:
+   - [rsa.c] bugfix: use correct size for memset()
+   - [sshconnect.c] warn if announced size of modulus 'n' != real size
+ - Added GNOME passphrase requestor (use --with-gnome-askpass)
+ - RPM build now creates subpackages
+ - Released 1.2pre9
+
+19991108
+ - Removed debian/ directory. This is now being maintained separately.
+ - Added symlinks for slogin in RPM spec file
+ - Fixed permissions on manpages in RPM spec file
+ - Added references to required libraries in README file
+ - Removed config.h.in from CVS
+ - Removed pwdb support (better pluggable auth is provided by glibc)
+ - Made PAM and requisite libdl optional
+ - Removed lots of unnecessary checks from autoconf
+ - Added support and autoconf test for openpty() function (Unix98 pty support)
+ - Fix for scp not finding ssh if not installed as /usr/bin/ssh
+ - Added TODO file
+ - Merged parts of Debian patch From Phil Hands <phil@hands.com>:
+   - Added ssh-askpass program
+   - Added ssh-askpass support to ssh-add.c
+   - Create symlinks for slogin on install
+   - Fix "distclean" target in makefile
+   - Added example for ssh-agent to manpage
+   - Added support for PAM_TEXT_INFO messages
+   - Disable internal /etc/nologin support if PAM enabled
+ - Merged latest OpenBSD CVS changes:
+   - [all] replace assert() with error, fatal or packet_disconnect
+   - [sshd.c] don't send fail-msg but disconnect if too many authentication
+     failures
+   - [sshd.c] remove unused argument. ok dugsong
+   - [sshd.c] typo
+   - [rsa.c] clear buffers used for encryption. ok: niels
+   - [rsa.c] replace assert() with error, fatal or packet_disconnect
+   - [auth-krb4.c] remove unused argument. ok dugsong
+ - Fixed coredump after merge of OpenBSD rsa.c patch
+ - Released 1.2pre8
+
+19991102
+ - Merged change from OpenBSD CVS
+  - One-line cleanup in sshd.c
+
+19991030
+ - Integrated debian package support from Dan Brosemer <odin@linuxfreak.com>
+ - Merged latest updates for OpenBSD CVS:
+   - channels.[ch] - remove broken x11 fix and document istate/ostate
+   - ssh-agent.c - call setsid() regardless of argv[]
+   - ssh.c - save a few lines when disabling rhosts-{rsa-}auth
+ - Documentation cleanups
+ - Renamed README -> README.Ylonen
+ - Renamed README.openssh ->README
+
+19991029
+ - Renamed openssh* back to ssh* at request of Theo de Raadt
+ - Incorporated latest changes from OpenBSD's CVS
+ - Integrated Makefile patch from  Niels Kristian Bech Jensen <nkbj@image.dk>
+ - Integrated PAM env patch from Nalin Dahyabhai <nalin.dahyabhai@pobox.com>
+ - Make distclean now removed configure script
+ - Improved PAM logging
+ - Added some debug() calls for PAM
+ - Removed redundant subdirectories
+ - Integrated part of a patch from Dan Brosemer <odin@linuxfreak.com> for
+   building on Debian.
+ - Fixed off-by-one error in PAM env patch
+ - Released 1.2pre6
+
+19991028
+ - Further PAM enhancements.
+   - Much cleaner
+   - Now uses account and session modules for all logins.
+ - Integrated patch from Dan Brosemer <odin@linuxfreak.com>
+   - Build fixes
+   - Autoconf
+   - Change binary names to open*
+ - Fixed autoconf script to detect PAM on RH6.1
+ - Added tests for libpwdb, and OpenBSD functions to autoconf
+ - Released 1.2pre4
+
+ - Imported latest OpenBSD CVS code
+ - Updated README.openssh
+ - Released 1.2pre5
+
+19991027
+ - Adapted PAM patch.
+ - Released 1.0pre2
+
+ - Excised my buggy replacements for strlcpy and mkdtemp
+ - Imported correct OpenBSD strlcpy and mkdtemp routines.
+ - Reduced arc4random_stir entropy read to 32 bytes (256 bits)
+ - Picked up correct version number from OpenBSD
+ - Added sshd.pam PAM configuration file
+ - Added sshd.init Redhat init script
+ - Added openssh.spec RPM spec file
+ - Released 1.2pre3
+
+19991026
+ - Fixed include paths of OpenSSL functions
+ - Use OpenSSL MD5 routines
+ - Imported RC4 code from nanocrypt
+ - Wrote replacements for OpenBSD arc4random* functions
+ - Wrote replacements for strlcpy and mkdtemp
+ - Released 1.0pre1
+
+$Id$
diff --git a/openssh/INSTALL b/openssh/INSTALL
new file mode 100644 (file)
index 0000000..777bdfe
--- /dev/null
@@ -0,0 +1,233 @@
+1. Prerequisites
+----------------
+
+You will need working installations of Zlib and OpenSSL.
+
+Zlib:
+http://www.gzip.org/zlib/ 
+
+OpenSSL 0.9.5a or greater:
+http://www.openssl.org/
+
+RPMs of OpenSSL are available at http://violet.ibs.com.au/openssh/files/support.
+For Red Hat Linux 6.2, they have been released as errata.  RHL7 includes
+these.
+
+OpenSSH can utilise Pluggable Authentication Modules (PAM) if your system
+supports it. PAM is standard on Redhat and Debian Linux, Solaris and
+HP-UX 11.
+
+PAM:
+http://www.kernel.org/pub/linux/libs/pam/
+
+If you wish to build the GNOME passphrase requester, you will need the GNOME
+libraries and headers.
+
+GNOME:
+http://www.gnome.org/
+
+Alternatively, Jim Knoble <jmknoble@jmknoble.cx> has written an excellent X11
+passphrase requester. This is maintained separately at:
+
+http://www.ntrnet.net/~jmknoble/software/x11-ssh-askpass/index.html
+
+PRNGD:
+
+If your system lacks Kernel based random collection, the use of Lutz 
+Jaenicke's PRNGd is recommended.
+
+http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html
+
+EGD:
+
+The Entropy Gathering Daemon (EGD) is supported if you have a system which
+lacks /dev/random and don't want to use OpenSSH's internal entropy collection.
+
+http://www.lothar.com/tech/crypto/
+
+GNU Make:
+ftp://ftp.gnu.org/gnu/make/
+
+OpenSSH has only been tested with GNU make. It may work with other
+'make' programs, but you are on your own.
+
+PCRE (PERL-compatible Regular Expression library):
+ftp://ftp.cus.cam.ac.uk/pub/software/programing/pcre/
+
+Most platforms do not require this.  However older Unices may not have a 
+posix regex library. PCRE provides a POSIX interface.
+
+S/Key Libraries:
+http://www.sparc.spb.su/solaris/skey/
+
+If you wish to use --with-skey then you will need the above library
+installed.  No other current S/Key library is currently known to be
+supported. 
+
+2. Building / Installation
+--------------------------
+
+To install OpenSSH with default options:
+
+./configure
+make
+make install
+
+This will install the OpenSSH binaries in /usr/local/bin, configuration files
+in /usr/local/etc, the server in /usr/local/sbin, etc. To specify a different
+installation prefix, use the --prefix option to configure:
+
+./configure --prefix=/opt
+make
+make install
+
+Will install OpenSSH in /opt/{bin,etc,lib,sbin}. You can also override 
+specific paths, for example:
+
+./configure --prefix=/opt --sysconfdir=/etc/ssh
+make
+make install
+
+This will install the binaries in /opt/{bin,lib,sbin}, but will place the
+configuration files in /etc/ssh.
+
+If you are using PAM, you may need to manually install a PAM control
+file as "/etc/pam.d/sshd" (or wherever your system prefers to keep
+them).  Note that the service name used to start PAM is __progname,
+which is the basename of the path of your sshd (e.g., the service name
+for /usr/sbin/osshd will be osshd).  If you have renamed your sshd
+executable, your PAM configuration may need to be modified.
+
+A generic PAM configuration is included as "contrib/sshd.pam.generic",
+you may need to edit it before using it on your system. If you are
+using a recent version of Red Hat Linux, the config file in
+contrib/redhat/sshd.pam should be more useful.  Failure to install a
+valid PAM file may result in an inability to use password
+authentication.  On HP-UX 11 and Solaris, the standard /etc/pam.conf
+configuration will work with sshd (sshd will match the other service
+name).
+
+There are a few other options to the configure script:
+
+--with-rsh=PATH allows you to specify the path to your rsh program. 
+Normally ./configure will search the current $PATH for 'rsh'. You 
+may need to specify this option if rsh is not in your path or has a
+different name.
+
+--with-pam enables PAM support.
+
+--enable-gnome-askpass will build the GNOME passphrase dialog. You
+need a working installation of GNOME, including the development
+headers, for this to work.
+
+--with-random=/some/file allows you to specify an alternate source of
+random numbers (the default is /dev/urandom). Unless you are absolutely
+sure of what you are doing, it is best to leave this alone.
+
+--with-prngd-socket=/some/file allows you to enable EGD or PRNGD 
+support and to specify a PRNGd socket. Use this if your Unix lacks 
+/dev/random and you don't want to use OpenSSH's builtin entropy 
+collection support.
+
+--with-prngd-port=portnum allows you to enable EGD or PRNGD support 
+and to specify a EGD localhost TCP port. Use this if your Unix lacks 
+/dev/random and you don't want to use OpenSSH's builtin entropy 
+collection support.
+
+--with-lastlog=FILE will specify the location of the lastlog file. 
+./configure searches a few locations for lastlog, but may not find
+it if lastlog is installed in a different place.
+
+--without-lastlog will disable lastlog support entirely.
+
+--with-sia, --without-sia will enable or disable OSF1's Security 
+Integration Architecture.  The default for OSF1 machines is enable.
+
+--with-kerberos4=PATH will enable Kerberos IV support. You will need
+to have the Kerberos libraries and header files installed for this
+to work. Use the optional PATH argument to specify the root of your
+Kerberos installation.
+
+--with-afs=PATH will enable AFS support. You will need to have the
+Kerberos IV and the AFS libraries and header files installed for this
+to work.  Use the optional PATH argument to specify the root of your
+AFS installation. AFS requires Kerberos support to be enabled.
+
+--with-skey=PATH will enable S/Key one time password support. You will 
+need the S/Key libraries and header files installed for this to work.
+
+--with-tcp-wrappers will enable TCP Wrappers (/etc/hosts.allow|deny)
+support. You will need libwrap.a and tcpd.h installed.
+
+--with-md5-passwords will enable the use of MD5 passwords. Enable this
+if your operating system uses MD5 passwords without using PAM.
+
+--with-utmpx enables utmpx support. utmpx support is automatic for 
+some platforms.
+
+--without-shadow disables shadow password support.
+
+--with-ipaddr-display forces the use of a numeric IP address in the 
+$DISPLAY environment variable. Some broken systems need this.
+
+--with-default-path=PATH allows you to specify a default $PATH for sessions
+started by sshd. This replaces the standard path entirely.
+
+--with-pid-dir=PATH specifies the directory in which the ssh.pid file is
+created.
+
+--with-xauth=PATH specifies the location of the xauth binary
+
+--with-ipv4-default instructs OpenSSH to use IPv4 by default for new
+connections. Normally OpenSSH will try attempt to lookup both IPv6 and
+IPv4 addresses. On Linux/glibc-2.1.2 this causes long delays in name
+resolution. If this option is specified, you can still attempt to 
+connect to IPv6 addresses using the command line option '-6'.
+
+--with-ssl-dir=DIR allows you to specify where your OpenSSL libraries
+are installed.
+
+--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to
+real (AF_INET) IPv4 addresses. Works around some quirks on Linux.
+
+If you need to pass special options to the compiler or linker, you
+can specify these as environment variables before running ./configure.
+For example:
+
+CFLAGS="-O -m486" LDFLAGS="-s" LIBS="-lrubbish" LD="/usr/foo/ld" ./configure
+
+3. Configuration
+----------------
+
+The runtime configuration files are installed by in ${prefix}/etc or 
+whatever you specified as your --sysconfdir (/usr/local/etc by default).
+
+The default configuration should be instantly usable, though you should 
+review it to ensure that it matches your security requirements.
+
+To generate a host key, run "make host-key". Alternately you can do so
+manually using the following commands: 
+
+    ssh-keygen -t rsa1 -f /etc/ssh/ssh_host_key -N ""
+    ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
+    ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ""
+
+Replacing /etc/ssh with the correct path to the configuration directory.
+(${prefix}/etc or whatever you specified with --sysconfdir during 
+configuration)
+
+If you have configured OpenSSH with EGD support, ensure that EGD is
+running and has collected some Entropy.
+
+For more information on configuration, please refer to the manual pages 
+for sshd, ssh and ssh-agent.
+
+4. Problems?
+------------
+
+If you experience problems compiling, installing or running OpenSSH. 
+Please refer to the "reporting bugs" section of the webpage at
+http://www.openssh.com/
+
+
+$Id$
diff --git a/openssh/LICENCE b/openssh/LICENCE
new file mode 100644 (file)
index 0000000..b229fcd
--- /dev/null
@@ -0,0 +1,174 @@
+This file is part of the OpenSSH software.
+
+The licences which components of this software fall under are as
+follows.  First, we will summarize and say that all components
+are under a BSD licence, or a licence more free than that.
+
+OpenSSH contains no GPL code.
+
+1)
+     * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+     *                    All rights reserved
+     *
+     * As far as I am concerned, the code I have written for this software
+     * can be used freely for any purpose.  Any derived versions of this
+     * software must be clearly marked as such, and if the derived work is
+     * incompatible with the protocol description in the RFC file, it must be
+     * called by a name other than "ssh" or "Secure Shell".
+
+    [Tatu continues]
+     *  However, I am not implying to give any licenses to any patents or
+     * copyrights held by third parties, and the software includes parts that
+     * are not under my direct control.  As far as I know, all included
+     * source code is used in accordance with the relevant license agreements
+     * and can be used freely for any purpose (the GNU license being the most
+     * restrictive); see below for details.
+
+    [However, none of that term is relevant at this point in time.  All of
+    these restrictively licenced software components which he talks about
+    have been removed from OpenSSH, i.e.,
+
+     - RSA is no longer included, found in the OpenSSL library
+     - IDEA is no longer included, its use is deprecated
+     - DES is now external, in the OpenSSL library
+     - GMP is no longer used, and instead we call BN code from OpenSSL
+     - Zlib is now external, in a library
+     - The make-ssh-known-hosts script is no longer included
+     - TSS has been removed
+     - MD5 is now external, in the OpenSSL library
+     - RC4 support has been replaced with ARC4 support from OpenSSL
+     - Blowfish is now external, in the OpenSSL library
+
+    [The licence continues]
+
+    Note that any information and cryptographic algorithms used in this
+    software are publicly available on the Internet and at any major
+    bookstore, scientific library, and patent office worldwide.  More
+    information can be found e.g. at "http://www.cs.hut.fi/crypto".
+    
+    The legal status of this program is some combination of all these
+    permissions and restrictions.  Use only at your own responsibility.
+    You will be responsible for any legal consequences yourself; I am not
+    making any claims whether possessing or using this is legal or not in
+    your country, and I am not taking any responsibility on your behalf.
+    
+    
+                           NO WARRANTY
+    
+    BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+    OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+    TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+    PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+    REPAIR OR CORRECTION.
+    
+    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+    OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+    TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+    YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+    PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+    POSSIBILITY OF SUCH DAMAGES.
+
+2)
+    The 32-bit CRC implementation in crc32.c is due to Gary S. Brown.
+    Comments in the file indicate it may be used for any purpose without
+    restrictions:
+
+     * COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+     * code or tables extracted from it, as desired without restriction.
+
+3)
+    The 32-bit CRC compensation attack detector in deattack.c was
+    contributed by CORE SDI S.A. under a BSD-style license.
+
+     * Cryptographic attack detector for ssh - source code
+     *
+     * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
+     *
+     * All rights reserved. Redistribution and use in source and binary
+     * forms, with or without modification, are permitted provided that
+     * this copyright notice is retained.
+     *
+     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+     * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
+     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
+     * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
+     * SOFTWARE.
+     *
+     * Ariel Futoransky <futo@core-sdi.com>
+     * <http://www.core-sdi.com>
+
+4)
+    ssh-keygen was contributed by David Mazieres under a BSD-style
+    license.
+
+     * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
+     *
+     * Modification and redistribution in source and binary forms is
+     * permitted provided that due credit is given to the author and the
+     * OpenBSD project by leaving this copyright notice intact.
+
+5)
+    The Rijndael implementation by Vincent Rijmen, Antoon Bosselaers
+    and Paulo Barreto is in the public domain and distributed
+    with the following license:
+
+     * @version 3.0 (December 2000)
+     * 
+     * Optimised ANSI C code for the Rijndael cipher (now AES)
+     * 
+     * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+     * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+     * @author Paulo Barreto <paulo.barreto@terra.com.br>
+     * 
+     * This code is hereby placed in the public domain.
+     * 
+     * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+     * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+     * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+     * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+    
+6)
+    Remaining components of the software are provided under a standard
+    2-term BSD licence with the following names as copyright holders:
+
+       Markus Friedl
+       Theo de Raadt
+       Niels Provos
+       Dug Song
+       Aaron Campbell
+       Damien Miller
+       Kevin Steves
+
+     * Redistribution and use in source and binary forms, with or without
+     * modification, are permitted provided that the following conditions
+     * are met:
+     * 1. Redistributions of source code must retain the above copyright
+     *    notice, this list of conditions and the following disclaimer.
+     * 2. Redistributions in binary form must reproduce the above copyright
+     *    notice, this list of conditions and the following disclaimer in the
+     *    documentation and/or other materials provided with the distribution.
+     *
+     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/openssh/Makefile.in b/openssh/Makefile.in
new file mode 100644 (file)
index 0000000..d20bfca
--- /dev/null
@@ -0,0 +1,304 @@
+# $Id$
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+libexecdir=@libexecdir@
+datadir=@datadir@
+mandir=@mandir@
+mansubdir=@mansubdir@
+sysconfdir=@sysconfdir@
+piddir=@piddir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+
+DESTDIR=
+VPATH=@srcdir@
+SSH_PROGRAM=@bindir@/ssh
+ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
+SFTP_SERVER=$(libexecdir)/sftp-server
+
+PATHS= -DETCDIR=\"$(sysconfdir)\" \
+       -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \
+       -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \
+       -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
+       -D_PATH_SSH_PIDDIR=\"$(piddir)\"
+
+CC=@CC@
+LD=@LD@
+CFLAGS=@CFLAGS@
+CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
+LIBS=@LIBS@
+AR=@AR@
+RANLIB=@RANLIB@
+INSTALL=@INSTALL@
+PERL=@PERL@
+ENT=@ENT@
+XAUTH_PATH=@XAUTH_PATH@
+LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
+EXEEXT=@EXEEXT@
+SSH_MODE= @SSHMODE@
+
+INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
+
+@NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
+
+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) $(SFTP_PROGS)
+
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o 
+
+SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o
+
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o
+
+MANPAGES       = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out
+MANPAGES_IN    = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1
+MANTYPE                = @MANTYPE@
+
+CONFIGFILES=sshd_config.out ssh_config.out moduli.out
+CONFIGFILES_IN=sshd_config ssh_config moduli
+
+PATHSUBS       = \
+       -D/etc/ssh_config=$(sysconfdir)/ssh_config \
+       -D/etc/ssh_known_hosts=$(sysconfdir)/ssh_known_hosts \
+       -D/etc/sshd_config=$(sysconfdir)/sshd_config \
+       -D/usr/libexec=$(libexecdir) \
+       -D/etc/shosts.equiv=$(sysconfdir)/shosts.equiv \
+       -D/etc/ssh_host_key=$(sysconfdir)/ssh_host_key \
+       -D/etc/ssh_host_dsa_key=$(sysconfdir)/ssh_host_dsa_key \
+       -D/etc/ssh_host_rsa_key=$(sysconfdir)/ssh_host_rsa_key \
+       -D/var/run/sshd.pid=$(piddir)/sshd.pid \
+       -D/etc/moduli=$(sysconfdir)/moduli \
+       -D/etc/sshrc=$(sysconfdir)/sshrc \
+       -D/usr/X11R6/bin/xauth=$(XAUTH_PATH) \
+       -D/usr/bin:/bin:/usr/sbin:/sbin=@user_path@
+
+FIXPATHSCMD    = $(PERL) $(srcdir)/fixpaths $(PATHSUBS)
+
+all: $(CONFIGFILES) $(MANPAGES) $(TARGETS)
+
+$(LIBSSH_OBJS): config.h
+$(SSHOBJS): config.h
+$(SSHDOBJS): config.h
+
+.c.o:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+
+LIBCOMPAT=openbsd-compat/libopenbsd-compat.a
+$(LIBCOMPAT): always
+       (cd openbsd-compat && $(MAKE))
+always:
+
+libssh.a: $(LIBSSH_OBJS)
+       $(AR) rv $@ $(LIBSSH_OBJS)
+       $(RANLIB) $@
+
+ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
+       $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+sshd$(EXEEXT): libssh.a        $(LIBCOMPAT) $(SSHDOBJS)
+       $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o
+       $(LD) -o $@ scp.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
+       $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+
+ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o
+       $(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+
+ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
+       $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+
+ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
+       $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) 
+
+sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o
+       $(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+
+sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o
+       $(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+# test driver for the loginrec code - not built by default
+logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
+       $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
+
+$(MANPAGES): $(MANPAGES_IN)
+       if test "$(MANTYPE)" = "cat"; then \
+               manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \
+       else \
+               manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \
+       fi; \
+       if test "$(MANTYPE)" = "man"; then \
+               $(FIXPATHSCMD) $${manpage} | $(PERL) $(srcdir)/mdoc2man.pl > $@; \
+       else \
+               $(FIXPATHSCMD) $${manpage} > $@; \
+       fi
+
+$(CONFIGFILES): $(CONFIGFILES_IN)
+       conffile=`echo $@ | sed 's/.out$$//'`; \
+       $(FIXPATHSCMD) $(srcdir)/$${conffile} > $@
+
+clean:
+       rm -f *.o *.a $(TARGETS) logintest config.cache config.log 
+       rm -f *.out core 
+       (cd openbsd-compat && $(MAKE) clean)
+
+distclean:
+       rm -f *.o *.a $(TARGETS) logintest config.cache config.log 
+       rm -f *.out core
+       rm -f Makefile config.h config.status ssh_prng_cmds *~
+       rm -rf autom4te.cache
+       (cd openbsd-compat && $(MAKE) distclean)
+       (cd scard && $(MAKE) distclean)
+
+veryclean:
+       rm -f configure config.h.in *.0
+       rm -f *.o *.a $(TARGETS) logintest config.cache config.log 
+       rm -f *.out core
+       rm -f Makefile config.h config.status ssh_prng_cmds *~
+       (cd openbsd-compat && $(MAKE) distclean)
+       (cd scard && $(MAKE) distclean)
+
+mrproper: distclean
+
+catman-do:
+       @for f in $(MANPAGES_IN) ; do \
+               base=`echo $$f | sed 's/\..*$$//'` ; \
+               echo "$$f -> $$base.0" ; \
+               nroff -mandoc $$f | cat -v | sed -e 's/.\^H//g' \
+                       >$$base.0 ; \
+       done
+
+distprep: catman-do
+       autoreconf
+       (cd scard && $(MAKE) -f Makefile.in distprep)
+
+install: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files host-key
+install-nokeys: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files
+
+scard-install:
+       (cd scard && $(MAKE) DESTDIR=$(DESTDIR) install)
+
+install-files: scard-install
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(sbindir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(datadir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)1
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)8
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(libexecdir)
+       $(INSTALL) -m $(SSH_MODE) -s ssh $(DESTDIR)$(bindir)/ssh
+       $(INSTALL) -m 0755 -s scp $(DESTDIR)$(bindir)/scp
+       $(INSTALL) -m 0755 -s ssh-add $(DESTDIR)$(bindir)/ssh-add
+       $(INSTALL) -m 0755 -s ssh-agent $(DESTDIR)$(bindir)/ssh-agent
+       $(INSTALL) -m 0755 -s ssh-keygen $(DESTDIR)$(bindir)/ssh-keygen
+       $(INSTALL) -m 0755 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan
+       $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd
+       @NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp
+       @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(SFTP_SERVER)
+       $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+       $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
+       $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
+       $(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
+       $(INSTALL) -m 644 ssh-keygen.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
+       $(INSTALL) -m 644 ssh-keyscan.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
+       $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
+       @NO_SFTP@$(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
+       @NO_SFTP@$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+       -rm -f $(DESTDIR)$(bindir)/slogin
+       ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+       ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+       #@FILEPRIV@ -f dev,filesys,driver $(DESTDIR)$(bindir)/ssh $(DESTDIR)$(bindir)/slogin
+       if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
+               $(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \
+       fi
+       if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config ]; then \
+               $(INSTALL) -m 644 ssh_config.out $(DESTDIR)$(sysconfdir)/ssh_config; \
+       else \
+               echo "$(DESTDIR)$(sysconfdir)/ssh_config already exists, install will not overwrite"; \
+       fi
+       if [ ! -f $(DESTDIR)$(sysconfdir)/sshd_config ]; then \
+               $(INSTALL) -m 644 sshd_config.out $(DESTDIR)$(sysconfdir)/sshd_config; \
+       else \
+               echo "$(DESTDIR)$(sysconfdir)/sshd_config already exists, install will not overwrite"; \
+       fi
+       if [ -f ssh_prng_cmds -a ! -z "$(INSTALL_SSH_PRNG_CMDS)" ]; then \
+               $(PERL) $(srcdir)/fixprogs ssh_prng_cmds $(ENT); \
+               if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_prng_cmds ] ; then \
+                       $(INSTALL) -m 644 ssh_prng_cmds.out $(DESTDIR)$(sysconfdir)/ssh_prng_cmds; \
+               else \
+                       echo "$(DESTDIR)$(sysconfdir)/ssh_prng_cmds already exists, install will not overwrite"; \
+               fi ; \
+       fi
+       if [ ! -f $(DESTDIR)$(sysconfdir)/moduli ]; then \
+               if [ -f $(DESTDIR)$(sysconfdir)/primes ]; then \
+                       echo "moving $(DESTDIR)$(sysconfdir)/primes to $(DESTDIR)$(sysconfdir)/moduli"; \
+                       mv "$(DESTDIR)$(sysconfdir)/primes" "$(DESTDIR)$(sysconfdir)/moduli"; \
+               else \
+                       $(INSTALL) -m 644 moduli.out $(DESTDIR)$(sysconfdir)/moduli; \
+               fi ; \
+       else \
+               echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \
+       fi
+
+host-key: ssh-keygen$(EXEEXT)
+       if [ -z "$(DESTDIR)" ] ; then \
+               if [ -f "$(DESTDIR)$(sysconfdir)/ssh_host_key" ] ; then \
+                       echo "$(DESTDIR)$(sysconfdir)/ssh_host_key already exists, skipping." ; \
+               else \
+                       ./ssh-keygen -t rsa1 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N "" ; \
+               fi ; \
+               if [ -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key ] ; then \
+                       echo "$(DESTDIR)$(sysconfdir)/ssh_host_dsa_key already exists, skipping." ; \
+               else \
+                       ./ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" ; \
+               fi ; \
+               if [ -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key ] ; then \
+                       echo "$(DESTDIR)$(sysconfdir)/ssh_host_rsa_key already exists, skipping." ; \
+               else \
+                       ./ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N "" ; \
+               fi ; \
+       fi ;
+
+host-key-force: ssh-keygen$(EXEEXT)
+       ./ssh-keygen -t rsa1 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N ""
+       ./ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N ""
+       ./ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N ""
+
+uninstallall:  uninstall
+       -rm -f $(DESTDIR)$(sysconfdir)/ssh_config
+       -rm -f $(DESTDIR)$(sysconfdir)/sshd_config
+       -rm -f $(DESTDIR)$(sysconfdir)/ssh_prng_cmds
+       -rmdir $(DESTDIR)$(sysconfdir)
+       -rmdir $(DESTDIR)$(bindir)
+       -rmdir $(DESTDIR)$(sbindir)
+       -rmdir $(DESTDIR)$(mandir)/$(mansubdir)1
+       -rmdir $(DESTDIR)$(mandir)/$(mansubdir)8
+       -rmdir $(DESTDIR)$(mandir)
+       -rmdir $(DESTDIR)$(libexecdir)
+
+uninstall: 
+       -rm -f $(DESTDIR)$(bindir)/slogin
+       -rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+       -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
+       -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
diff --git a/openssh/OVERVIEW b/openssh/OVERVIEW
new file mode 100644 (file)
index 0000000..ff03eca
--- /dev/null
@@ -0,0 +1,170 @@
+[Note: This file has not been updated for OpenSSH versions after
+OpenSSH-1.2 and should be considered OBSOLETE.  It has been left in
+the distribution because some of its information may still be useful
+to developers.]
+
+This document is intended for those who wish to read the ssh source
+code.  This tries to give an overview of the structure of the code.
+      
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>
+Updated 17 Nov 1995.
+Updated 19 Oct 1999 for OpenSSH-1.2
+Updated 20 May 2001 note obsolete for > OpenSSH-1.2
+
+The software consists of ssh (client), sshd (server), scp, sdist, and
+the auxiliary programs ssh-keygen, ssh-agent, ssh-add, and
+make-ssh-known-hosts.  The main program for each of these is in a .c
+file with the same name.
+
+There are some subsystems/abstractions that are used by a number of
+these programs.
+
+  Buffer manipulation routines
+      
+    - These provide an arbitrary size buffer, where data can be appended.
+      Data can be consumed from either end.  The code is used heavily
+      throughout ssh.  The basic buffer manipulation functions are in
+      buffer.c (header buffer.h), and additional code to manipulate specific
+      data types is in bufaux.c.
+
+  Compression Library
+  
+    - Ssh uses the GNU GZIP compression library (ZLIB).
+
+  Encryption/Decryption
+
+    - Ssh contains several encryption algorithms.  These are all
+      accessed through the cipher.h interface.  The interface code is
+      in cipher.c, and the implementations are in libc.
+
+  Multiple Precision Integer Library
+
+    - Uses the SSLeay BIGNUM sublibrary.
+    - Some auxiliary functions for mp-int manipulation are in mpaux.c.
+
+  Random Numbers
+
+    - Uses arc4random() and such.
+
+  RSA key generation, encryption, decryption
+
+    - Ssh uses the RSA routines in libssl.
+
+  RSA key files
+
+    - RSA keys are stored in files with a special format.  The code to
+      read/write these files is in authfile.c.  The files are normally
+      encrypted with a passphrase.  The functions to read passphrases
+      are in readpass.c (the same code is used to read passwords).
+
+  Binary packet protocol
+
+    - The ssh binary packet protocol is implemented in packet.c.  The
+      code in packet.c does not concern itself with packet types or their
+      execution; it contains code to build packets, to receive them and
+      extract data from them, and the code to compress and/or encrypt
+      packets.  CRC code comes from crc32.c.
+
+    - The code in packet.c calls the buffer manipulation routines
+      (buffer.c, bufaux.c), compression routines (compress.c, zlib),
+      and the encryption routines.
+
+  X11, TCP/IP, and Agent forwarding
+
+    - Code for various types of channel forwarding is in channels.c.
+      The file defines a generic framework for arbitrary communication
+      channels inside the secure channel, and uses this framework to
+      implement X11 forwarding, TCP/IP forwarding, and authentication
+      agent forwarding.
+      The new, Protocol 1.5, channel close implementation is in nchan.c
+
+  Authentication agent
+
+    - Code to communicate with the authentication agent is in authfd.c.
+
+  Authentication methods
+
+    - Code for various authentication methods resides in auth-*.c
+      (auth-passwd.c, auth-rh-rsa.c, auth-rhosts.c, auth-rsa.c).  This
+      code is linked into the server.  The routines also manipulate
+      known hosts files using code in hostfile.c.  Code in canohost.c
+      is used to retrieve the canonical host name of the remote host.
+      Code in match.c is used to match host names.  
+
+    - In the client end, authentication code is in sshconnect.c.  It
+      reads Passwords/passphrases using code in readpass.c.  It reads
+      RSA key files with authfile.c.  It communicates the
+      authentication agent using authfd.c.
+
+  The ssh client
+
+    - The client main program is in ssh.c.  It first parses arguments
+      and reads configuration (readconf.c), then calls ssh_connect (in
+      sshconnect.c) to open a connection to the server (possibly via a
+      proxy), and performs authentication (ssh_login in sshconnect.c).
+      It then makes any pty, forwarding, etc. requests.  It may call
+      code in ttymodes.c to encode current tty modes.  Finally it
+      calls client_loop in clientloop.c.  This does the real work for
+      the session.
+
+    - The client is suid root.  It tries to temporarily give up this
+      rights while reading the configuration data.  The root
+      privileges are only used to make the connection (from a
+      privileged socket).  Any extra privileges are dropped before
+      calling ssh_login.
+
+  Pseudo-tty manipulation and tty modes
+
+    - Code to allocate and use a pseudo tty is in pty.c.  Code to
+      encode and set terminal modes is in ttymodes.c.
+
+  Logging in (updating utmp, lastlog, etc.)
+
+    - The code to do things that are done when a user logs in are in
+      login.c.  This includes things such as updating the utmp, wtmp,
+      and lastlog files.  Some of the code is in sshd.c.
+
+  Writing to the system log and terminal
+
+    - The programs use the functions fatal(), log(), debug(), error()
+      in many places to write messages to system log or user's
+      terminal.  The implementation that logs to system log is in
+      log-server.c; it is used in the server program.  The other
+      programs use an implementation that sends output to stderr; it
+      is in log-client.c.  The definitions are in ssh.h.
+
+  The sshd server (daemon)
+
+    - The sshd daemon starts by processing arguments and reading the
+      configuration file (servconf.c).  It then reads the host key,
+      starts listening for connections, and generates the server key.
+      The server key will be regenerated every hour by an alarm.
+
+    - When the server receives a connection, it forks, disables the
+      regeneration alarm, and starts communicating with the client.
+      They first perform identification string exchange, then
+      negotiate encryption, then perform authentication, preparatory
+      operations, and finally the server enters the normal session
+      mode by calling server_loop in serverloop.c.  This does the real
+      work, calling functions in other modules.
+      
+    - The code for the server is in sshd.c.  It contains a lot of
+      stuff, including:
+        - server main program
+       - waiting for connections
+       - processing new connection
+       - authentication
+       - preparatory operations
+       - building up the execution environment for the user program
+       - starting the user program.
+
+  Auxiliary files
+
+    - There are several other files in the distribution that contain
+      various auxiliary routines:
+        ssh.h       the main header file for ssh (various definitions)
+        getput.h     byte-order independent storage of integers
+        includes.h   includes most system headers.  Lots of #ifdefs.
+       tildexpand.c expand tilde in file names
+       uidswap.c    uid-swapping
+       xmalloc.c    "safe" malloc routines
diff --git a/openssh/README b/openssh/README
new file mode 100644 (file)
index 0000000..979d1d5
--- /dev/null
@@ -0,0 +1,66 @@
+- A Japanese translation of this document and of the OpenSSH FAQ is 
+- available at http://www.unixuser.org/~haruyama/security/openssh/index.html
+- Thanks to HARUYAMA Seigo <haruyama@klab.org>
+
+This is the port of OpenBSD's excellent OpenSSH[0] to Linux and other
+Unices.
+
+OpenSSH is based on the last free version of Tatu Ylonen's sample
+implementation with all patent-encumbered algorithms removed (to
+external libraries), all known security bugs fixed, new features
+reintroduced and many other clean-ups.  OpenSSH has been created by
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt,
+and Dug Song. It has a homepage at http://www.openssh.com/
+
+This port consists of the re-introduction of autoconf support, PAM
+support (for Linux and Solaris), EGD[1]/PRNGD[2] support and replacements 
+for OpenBSD library functions that are (regrettably) absent from other 
+unices. This port has been best tested on Linux, Solaris, HP-UX, NetBSD 
+and Irix. Support for AIX, SCO, NeXT and other Unices is underway. 
+This version actively tracks changes in the OpenBSD CVS repository.
+
+The PAM support is now more functional than the popular packages of
+commercial ssh-1.2.x. It checks "account" and "session" modules for
+all logins, not just when using password authentication.
+
+OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5].
+
+There is now several mailing lists for this port of OpenSSH. Please
+refer to http://www.openssh.com/list.html for details on how to join.
+
+Please send bug reports and patches to the mailing list
+openssh-unix-dev@mindrot.org. The list is open to posting by
+unsubscribed users.
+
+If you are a citizen of an USA-embargoed country to which export of 
+cryptographic products is restricted, then please refrain from sending 
+crypto-related code or patches to the list. We cannot accept them.
+Other code contribution are accepted, but please follow the OpenBSD
+style guidelines[6].
+
+Please refer to the INSTALL document for information on how to install
+OpenSSH on your system. There are a number of differences between this 
+port of OpenSSH and F-Secure SSH 1.x, please refer to the OpenSSH FAQ[7]
+for details and general tips.
+
+Damien Miller <djm@mindrot.org>
+
+Miscellania - 
+
+This version of OpenSSH is based upon code retrieved from the OpenBSD
+CVS repository which in turn was based on the last free sample
+implementation released by Tatu Ylonen.
+
+References -
+
+[0] http://www.openssh.com/faq.html
+[1] http://www.lothar.com/tech/crypto/
+[2] http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html
+[3] http://www.gzip.org/zlib/
+[4] http://www.openssl.org/
+[5] http://www.kernel.org/pub/linux/libs/pam/ (PAM is standard on Solaris
+    and HP-UX 11)
+[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9
+[7] http://www.openssh.com/faq.html
+
+$Id$
diff --git a/openssh/README.smartcard b/openssh/README.smartcard
new file mode 100644 (file)
index 0000000..69dca15
--- /dev/null
@@ -0,0 +1,72 @@
+How to use smartcards with OpenSSH?
+
+OpenSSH contains experimental support for authentication using
+Cyberflex smartcards and TODOS card readers. 
+
+WARNING: Smartcard support is still in development. Keyfile formats, etc
+are still subject to change.
+
+To enable this you need to:
+
+(1) install sectok
+
+       Sources are instructions are available from
+       http://www.citi.umich.edu/projects/smartcard/sectok.html
+
+(2) enable SMARTCARD support in OpenSSH:
+
+       $ ./configure --with-smartcard [options]
+
+       You can also specify a path to libsectok:
+
+       $ ./configure --with-smartcard=/path/to/libsectok [options]
+
+(3) load the Java Cardlet to the Cyberflex card:
+
+       $ sectok
+       sectok> login -d
+       sectok> jload /usr/libdata/ssh/Ssh.bin
+       sectok> quit
+
+(4) load a RSA key to the card:
+
+       please don't use your production RSA keys, since
+       with the current version of sectok/ssh-keygen
+       the private key file is still readable
+
+       $ ssh-keygen -f /path/to/rsakey -U 1
+       (where 1 is the reader number, you can also try 0)
+
+       In spite of the name, this does not generate a key.
+       It just loads an already existing key on to the card.
+
+(5) optional:
+
+       Change the card password so that only you can
+       read the private key:
+
+       $ sectok
+       sectok> login -d
+       sectok> setpass
+       sectok> quit
+
+       This prevents reading the key but not use of the
+       key by the card applet.
+
+       Do not forget the passphrase.  There is no way to
+       recover if you do.
+
+       IMPORTANT WARNING: If you attempt to login with the
+       wrong passphrase three times in a row, you will
+       destroy your card.
+
+(6) tell the ssh client to use the card reader:
+
+       $ ssh -I 1 otherhost
+
+(7) or tell the agent (don't forget to restart) to use the smartcard:
+
+       $ ssh-add -s 1
+
+-markus,
+Tue Jul 17 23:54:51 CEST 2001
diff --git a/openssh/RFC.nroff b/openssh/RFC.nroff
new file mode 100644 (file)
index 0000000..bf7146a
--- /dev/null
@@ -0,0 +1,1780 @@
+.\" -*- nroff -*-
+.\"
+.\" $OpenBSD: RFC.nroff,v 1.2 2000/10/16 09:38:44 djm Exp $
+.\"
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Ylonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet-Draft
+.ds RH 15 November 1995
+.ds CH SSH (Secure Shell) Remote Login Protocol
+.na
+.hy 0
+.in 0
+Network Working Group                                         T. Ylonen
+Internet-Draft                        Helsinki University of Technology
+draft-ylonen-ssh-protocol-00.txt                       15 November 1995
+Expires: 15 May 1996
+
+.in 3
+
+.ce
+The SSH (Secure Shell) Remote Login Protocol
+
+.ti 0
+Status of This Memo
+
+This document is an Internet-Draft.   Internet-Drafts  are  working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups.  Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid  for  a  maximum  of  six
+months  and  may  be updated, replaced, or obsoleted by other docu-
+ments at any time.  It is inappropriate to use  Internet-Drafts  as
+reference  material  or  to  cite them other than as ``work in pro-
+gress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet- Drafts Shadow
+Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of  this  memo  is  unlimited.
+
+.ti 0
+Introduction
+
+SSH (Secure Shell) is a program to log into another computer over a
+network, to execute commands in a remote machine, and to move files
+from one machine to another.  It provides strong authentication and
+secure communications over insecure networks.  Its features include
+the following:
+.IP o
+Closes several security holes (e.g., IP, routing, and DNS spoofing).
+New authentication methods: .rhosts together with RSA [RSA] based host
+authentication, and pure RSA authentication.
+.IP o
+All communications are automatically and transparently encrypted.
+Encryption is also used to protect integrity.
+.IP o
+X11 connection forwarding provides secure X11 sessions.
+.IP o
+Arbitrary TCP/IP ports can be redirected over the encrypted channel
+in both directions.
+.IP o
+Client RSA-authenticates the server machine in the beginning of every
+connection to prevent trojan horses (by routing or DNS spoofing) and
+man-in-the-middle attacks, and the server RSA-authenticates the client
+machine before accepting .rhosts or /etc/hosts.equiv authentication
+(to prevent DNS, routing, or IP spoofing).
+.IP o
+An authentication agent, running in the user's local workstation or
+laptop, can be used to hold the user's RSA authentication keys.
+.RT
+
+The goal has been to make the software as easy to use as possible for
+ordinary users.  The protocol has been designed to be as secure as
+possible while making it possible to create implementations that
+are easy to use and install.  The sample implementation has a number
+of convenient features that are not described in this document as they
+are not relevant for the protocol.
+
+
+.ti 0
+Overview of the Protocol
+
+The software consists of a server program running on a server machine,
+and a client program running on a client machine (plus a few auxiliary
+programs).  The machines are connected by an insecure IP [RFC0791]
+network (that can be monitored, tampered with, and spoofed by hostile
+parties).
+
+A connection is always initiated by the client side.  The server
+listens on a specific port waiting for connections.  Many clients may
+connect to the same server machine.
+
+The client and the server are connected via a TCP/IP [RFC0793] socket
+that is used for bidirectional communication.  Other types of
+transport can be used but are currently not defined.
+
+When the client connects the server, the server accepts the connection
+and responds by sending back its version identification string.  The
+client parses the server's identification, and sends its own
+identification.  The purpose of the identification strings is to
+validate that the connection was to the correct port, declare the
+protocol version number used, and to declare the software version used
+on each side (for debugging purposes).  The identification strings are
+human-readable.  If either side fails to understand or support the
+other side's version, it closes the connection.
+
+After the protocol identification phase, both sides switch to a packet
+based binary protocol.  The server starts by sending its host key
+(every host has an RSA key used to authenticate the host), server key
+(an RSA key regenerated every hour), and other information to the
+client.  The client then generates a 256 bit session key, encrypts it
+using both RSA keys (see below for details), and sends the encrypted
+session key and selected cipher type to the server.  Both sides then
+turn on encryption using the selected algorithm and key.  The server
+sends an encrypted confirmation message to the client.
+
+The client then authenticates itself using any of a number of
+authentication methods.  The currently supported authentication
+methods are .rhosts or /etc/hosts.equiv authentication (disabled by
+default), the same with RSA-based host authentication, RSA
+authentication, and password authentication.
+
+After successful authentication, the client makes a number of requests
+to prepare for the session.  Typical requests include allocating a
+pseudo tty, starting X11 [X11] or TCP/IP port forwarding, starting
+authentication agent forwarding, and executing the shell or a command.
+
+When a shell or command is executed, the connection enters interactive
+session mode.  In this mode, data is passed in both directions, 
+new forwarded connections may be opened, etc.  The interactive session
+normally terminates when the server sends the exit status of the
+program to the client.
+
+
+The protocol makes several reservations for future extensibility.
+First of all, the initial protocol identification messages include the
+protocol version number.  Second, the first packet by both sides
+includes a protocol flags field, which can be used to agree on
+extensions in a compatible manner.  Third, the authentication and
+session preparation phases work so that the client sends requests to
+the server, and the server responds with success or failure.  If the
+client sends a request that the server does not support, the server
+simply returns failure for it.  This permits compatible addition of
+new authentication methods and preparation operations.  The
+interactive session phase, on the other hand, works asynchronously and
+does not permit the use of any extensions (because there is no easy
+and reliable way to signal rejection to the other side and problems
+would be hard to debug).  Any compatible extensions to this phase must
+be agreed upon during any of the earlier phases.
+
+.ti 0
+The Binary Packet Protocol
+
+After the protocol identification strings, both sides only send
+specially formatted packets.  The packet layout is as follows:
+.IP o
+Packet length: 32 bit unsigned integer, coded as four 8-bit bytes, msb
+first.  Gives the length of the packet, not including the length field
+and padding.  The maximum length of a packet (not including the length
+field and padding) is 262144 bytes.
+.IP o
+Padding: 1-8 bytes of random data (or zeroes if not encrypting).  The
+amount of padding is (8 - (length % 8)) bytes (where % stands for the
+modulo operator).  The rationale for always having some random padding
+at the beginning of each packet is to make known plaintext attacks
+more difficult.
+.IP o
+Packet type: 8-bit unsigned byte.  The value 255 is reserved for
+future extension.
+.IP o
+Data: binary data bytes, depending on the packet type.  The number of
+data bytes is the "length" field minus 5.
+.IP o
+Check bytes: 32-bit crc, four 8-bit bytes, msb first.  The crc is the
+Cyclic Redundancy Check, with the polynomial 0xedb88320, of the
+Padding, Packet type, and Data fields.  The crc is computed before
+any encryption.
+.RT
+
+The packet, except for the length field, may be encrypted using any of
+a number of algorithms.  The length of the encrypted part (Padding +
+Type + Data + Check) is always a multiple of 8 bytes.  Typically the
+cipher is used in a chained mode, with all packets chained together as
+if it was a single data stream (the length field is never included in
+the encryption process).  Details of encryption are described below.
+
+When the session starts, encryption is turned off.  Encryption is
+enabled after the client has sent the session key.  The encryption
+algorithm to use is selected by the client.
+
+
+.ti 0
+Packet Compression
+
+If compression is supported (it is an optional feature, see
+SSH_CMSG_REQUEST_COMPRESSION below), the packet type and data fields
+of the packet are compressed using the gzip deflate algorithm [GZIP].
+If compression is in effect, the packet length field indicates the
+length of the compressed data, plus 4 for the crc.  The amount of
+padding is computed from the compressed data, so that the amount of
+data to be encrypted becomes a multiple of 8 bytes.
+
+When compressing, the packets (type + data portions) in each direction
+are compressed as if they formed a continuous data stream, with only the
+current compression block flushed between packets.  This corresponds
+to the GNU ZLIB library Z_PARTIAL_FLUSH option.  The compression
+dictionary is not flushed between packets.  The two directions are
+compressed independently of each other.
+
+
+.ti 0
+Packet Encryption
+
+The protocol supports several encryption methods.  During session
+initialization, the server sends a bitmask of all encryption methods
+that it supports, and the client selects one of these methods.  The
+client also generates a 256-bit random session key (32 8-bit bytes) and
+sends it to the server.
+
+The encryption methods supported by the current implementation, and
+their codes are:
+.TS
+center;
+l r l.
+SSH_CIPHER_NONE        0          No encryption
+SSH_CIPHER_IDEA        1          IDEA in CFB mode
+SSH_CIPHER_DES 2          DES in CBC mode
+SSH_CIPHER_3DES        3          Triple-DES in CBC mode
+SSH_CIPHER_TSS 4          An experimental stream cipher
+SSH_CIPHER_RC4 5          RC4
+.TE
+
+All implementations are required to support SSH_CIPHER_DES and
+SSH_CIPHER_3DES.  Supporting SSH_CIPHER_IDEA, SSH_CIPHER_RC4, and
+SSH_CIPHER_NONE is recommended.  Support for SSH_CIPHER_TSS is
+optional (and it is not described in this document).  Other ciphers
+may be added at a later time; support for them is optional.
+
+For encryption, the encrypted portion of the packet is considered a
+linear byte stream.  The length of the stream is always a multiple of
+8.  The encrypted portions of consecutive packets (in the same
+direction) are encrypted as if they were a continuous buffer (that is,
+any initialization vectors are passed from the previous packet to the
+next packet).  Data in each direction is encrypted independently.
+.IP SSH_CIPHER_DES
+The key is taken from the first 8 bytes of the session key.  The least
+significant bit of each byte is ignored.  This results in 56 bits of
+key data.  DES [DES] is used in CBC mode.  The iv (initialization vector) is
+initialized to all zeroes.
+.IP SSH_CIPHER_3DES
+The variant of triple-DES used here works as follows: there are three
+independent DES-CBC ciphers, with independent initialization vectors.
+The data (the whole encrypted data stream) is first encrypted with the
+first cipher, then decrypted with the second cipher, and finally
+encrypted with the third cipher.  All these operations are performed
+in CBC mode.
+
+The key for the first cipher is taken from the first 8 bytes of the
+session key; the key for the next cipher from the next 8 bytes, and
+the key for the third cipher from the following 8 bytes.  All three
+initialization vectors are initialized to zero.
+
+(Note: the variant of 3DES used here differs from some other
+descriptions.)
+.IP SSH_CIPHER_IDEA
+The key is taken from the first 16 bytes of the session key.  IDEA
+[IDEA] is used in CFB mode.  The initialization vector is initialized
+to all zeroes.
+.IP SSH_CIPHER_TSS
+All 32 bytes of the session key are used as the key.
+
+There is no reference available for the TSS algorithm; it is currently
+only documented in the sample implementation source code.  The
+security of this cipher is unknown (but it is quite fast).  The cipher
+is basically a stream cipher that uses MD5 as a random number
+generator and takes feedback from the data.
+.IP SSH_CIPHER_RC4
+The first 16 bytes of the session key are used as the key for the
+server to client direction.  The remaining 16 bytes are used as the
+key for the client to server direction.  This gives independent
+128-bit keys for each direction.
+
+This algorithm is the alleged RC4 cipher posted to the Usenet in 1995.
+It is widely believed to be equivalent with the original RSADSI RC4
+cipher.  This is a very fast algorithm.
+.RT
+
+
+.ti 0
+Data Type Encodings
+
+The Data field of each packet contains data encoded as described in
+this section.  There may be several data items; each item is coded as
+described here, and their representations are concatenated together
+(without any alignment or padding).
+
+Each data type is stored as follows:
+.IP "8-bit byte"
+The byte is stored directly as a single byte.
+.IP "32-bit unsigned integer"
+Stored in 4 bytes, msb first.
+.IP "Arbitrary length binary string"
+First 4 bytes are the length of the string, msb first (not including
+the length itself).  The following "length" bytes are the string
+value.  There are no terminating null characters.
+.IP "Multiple-precision integer"
+First 2 bytes are the number of bits in the integer, msb first (for
+example, the value 0x00012345 would have 17 bits).  The value zero has
+zero bits.  It is permissible that the number of bits be larger than the
+real number of bits.
+
+The number of bits is followed by (bits + 7) / 8 bytes of binary data,
+msb first, giving the value of the integer.
+.RT
+
+
+.ti 0
+TCP/IP Port Number and Other Options
+
+The server listens for connections on TCP/IP port 22.
+
+The client may connect the server from any port.  However, if the
+client wishes to use any form of .rhosts or /etc/hosts.equiv
+authentication, it must connect from a privileged port (less than
+1024).
+
+For the IP Type of Service field [RFC0791], it is recommended that
+interactive sessions (those having a user terminal or forwarding X11
+connections) use the IPTOS_LOWDELAY, and non-interactive connections
+use IPTOS_THROUGHPUT.
+
+It is recommended that keepalives are used, because otherwise programs
+on the server may never notice if the other end of the connection is
+rebooted.
+
+
+.ti 0
+Protocol Version Identification
+
+After the socket is opened, the server sends an identification string,
+which is of the form
+"SSH-<protocolmajor>.<protocolminor>-<version>\\n", where
+<protocolmajor> and <protocolminor> are integers and specify the
+protocol version number (not software distribution version).
+<version> is server side software version string (max 40 characters);
+it is not interpreted by the remote side but may be useful for
+debugging.
+
+The client parses the server's string, and sends a corresponding
+string with its own information in response.  If the server has lower
+version number, and the client contains special code to emulate it,
+the client responds with the lower number; otherwise it responds with
+its own number.  The server then compares the version number the
+client sent with its own, and determines whether they can work
+together.  The server either disconnects, or sends the first packet
+using the binary packet protocol and both sides start working
+according to the lower of the protocol versions.
+
+By convention, changes which keep the protocol compatible with
+previous versions keep the same major protocol version; changes that
+are not compatible increment the major version (which will hopefully
+never happen).  The version described in this document is 1.3.
+
+The client will 
+
+.ti 0
+Key Exchange and Server Host Authentication
+
+The first message sent by the server using the packet protocol is
+SSH_SMSG_PUBLIC_KEY.  It declares the server's host key, server public
+key, supported ciphers, supported authentication methods, and flags
+for protocol extensions.  It also contains a 64-bit random number
+(cookie) that must be returned in the client's reply (to make IP
+spoofing more difficult).  No encryption is used for this message.
+
+Both sides compute a session id as follows.  The modulus of the server
+key is interpreted as a byte string (without explicit length field,
+with minimum length able to hold the whole value), most significant
+byte first.  This string is concatenated with the server host key
+interpreted the same way.  Additionally, the cookie is concatenated
+with this.  Both sides compute MD5 of the resulting string.  The
+resulting 16 bytes (128 bits) are stored by both parties and are
+called the session id.
+
+The client responds with a SSH_CMSG_SESSION_KEY message, which
+contains the selected cipher type, a copy of the 64-bit cookie sent by
+the server, client's protocol flags, and a session key encrypted
+with both the server's host key and server key.  No encryption is used
+for this message.
+
+The session key is 32 8-bit bytes (a total of 256 random bits
+generated by the client).  The client first xors the 16 bytes of the
+session id with the first 16 bytes of the session key.  The resulting
+string is then encrypted using the smaller key (one with smaller
+modulus), and the result is then encrypted using the other key.  The
+number of bits in the public modulus of the two keys must differ by at
+least 128 bits.
+
+At each encryption step, a multiple-precision integer is constructed
+from the data to be encrypted as follows (the integer is here
+interpreted as a sequence of bytes, msb first; the number of bytes is
+the number of bytes needed to represent the modulus).
+
+The most significant byte (which is only partial as the value must be
+less than the public modulus, which is never a power of two) is zero.
+
+The next byte contains the value 2 (which stands for public-key
+encrypted data in the PKCS standard [PKCS#1]).  Then, there are
+non-zero random bytes to fill any unused space, a zero byte, and the
+data to be encrypted in the least significant bytes, the last byte of
+the data in the least significant byte.
+
+This algorithm is used twice.  First, it is used to encrypt the 32
+random bytes generated by the client to be used as the session key
+(xored by the session id).  This value is converted to an integer as
+described above, and encrypted with RSA using the key with the smaller
+modulus.  The resulting integer is converted to a byte stream, msb
+first.  This byte stream is padded and encrypted identically using the
+key with the larger modulus.
+
+After the client has sent the session key, it starts to use the
+selected algorithm and key for decrypting any received packets, and
+for encrypting any sent packets.  Separate ciphers are used for
+different directions (that is, both directions have separate
+initialization vectors or other state for the ciphers).
+
+When the server has received the session key message, and has turned
+on encryption, it sends a SSH_SMSG_SUCCESS message to the client.
+
+The recommended size of the host key is 1024 bits, and 768 bits for
+the server key.  The minimum size is 512 bits for the smaller key.
+
+
+.ti 0
+Declaring the User Name
+
+The client then sends a SSH_CMSG_USER message to the server.  This
+message specifies the user name to log in as.
+
+The server validates that such a user exists, checks whether
+authentication is needed, and responds with either SSH_SMSG_SUCCESS or
+SSH_SMSG_FAILURE.  SSH_SMSG_SUCCESS indicates that no authentication
+is needed for this user (no password), and authentication phase has
+now been completed.  SSH_SMSG_FAILURE indicates that authentication is
+needed (or the user does not exist).
+
+If the user does not exist, it is recommended that this returns
+failure, but the server keeps reading messages from the client, and
+responds to any messages (except SSH_MSG_DISCONNECT, SSH_MSG_IGNORE,
+and SSH_MSG_DEBUG) with SSH_SMSG_FAILURE.  This way the client cannot
+be certain whether the user exists.
+
+
+.ti 0
+Authentication Phase
+
+Provided the server didn't immediately accept the login, an
+authentication exchange begins.  The client sends messages to the
+server requesting different types of authentication in arbitrary order as
+many times as desired (however, the server may close the connection
+after a timeout).  The server always responds with SSH_SMSG_SUCCESS if
+it has accepted the authentication, and with SSH_SMSG_FAILURE if it has
+denied authentication with the requested method or it does not
+recognize the message.  Some authentication methods cause an exchange
+of further messages before the final result is sent.  The
+authentication phase ends when the server responds with success.
+
+The recommended value for the authentication timeout (timeout before
+disconnecting if no successful authentication has been made) is 5
+minutes.
+
+The following authentication methods are currently supported:
+.TS
+center;
+l r l.
+SSH_AUTH_RHOSTS        1       .rhosts or /etc/hosts.equiv
+SSH_AUTH_RSA   2       pure RSA authentication
+SSH_AUTH_PASSWORD      3       password authentication
+SSH_AUTH_RHOSTS_RSA    4       .rhosts with RSA host authentication
+.TE
+.IP SSH_AUTH_RHOSTS
+
+This is the authentication method used by rlogin and rsh [RFC1282].
+
+The client sends SSH_CMSG_AUTH_RHOSTS with the client-side user name
+as an argument.
+
+The server checks whether to permit authentication.  On UNIX systems,
+this is usually done by checking /etc/hosts.equiv, and .rhosts in the
+user's home directory.  The connection must come from a privileged
+port.
+
+It is recommended that the server checks that there are no IP options
+(such as source routing) specified for the socket before accepting
+this type of authentication.  The client host name should be
+reverse-mapped and then forward mapped to ensure that it has the
+proper IP-address.
+
+This authentication method trusts the remote host (root on the remote
+host can pretend to be any other user on that host), the name
+services, and partially the network: anyone who can see packets coming
+out from the server machine can do IP-spoofing and pretend to be any
+machine; however, the protocol prevents blind IP-spoofing (which used
+to be possible with rlogin).
+
+Many sites probably want to disable this authentication method because
+of the fundamental insecurity of conventional .rhosts or
+/etc/hosts.equiv authentication when faced with spoofing.  It is
+recommended that this method not be supported by the server by
+default.
+.IP SSH_AUTH_RHOSTS_RSA
+
+In addition to conventional .rhosts and hosts.equiv authentication,
+this method additionally requires that the client host be
+authenticated using RSA.
+
+The client sends SSH_CMSG_AUTH_RHOSTS_RSA specifying the client-side
+user name, and the public host key of the client host.
+
+The server first checks if normal .rhosts or /etc/hosts.equiv
+authentication would be accepted, and if not, responds with
+SSH_SMSG_FAILURE.  Otherwise, it checks whether it knows the host key
+for the client machine (using the same name for the host that was used
+for checking the .rhosts and /etc/hosts.equiv files).  If it does not
+know the RSA key for the client, access is denied and SSH_SMSG_FAILURE
+is sent.
+
+If the server knows the host key of the client machine, it verifies
+that the given host key matches that known for the client.  If not,
+access is denied and SSH_SMSG_FAILURE is sent.
+
+The server then sends a SSH_SMSG_AUTH_RSA_CHALLENGE message containing
+an encrypted challenge for the client.  The challenge is 32 8-bit
+random bytes (256 bits).  When encrypted, the highest (partial) byte
+is left as zero, the next byte contains the value 2, the following are
+non-zero random bytes, followed by a zero byte, and the challenge put
+in the remaining bytes.  This is then encrypted using RSA with the
+client host's public key.  (The padding and encryption algorithm is
+the same as that used for the session key.)
+
+The client decrypts the challenge using its private host key,
+concatenates this with the session id, and computes an MD5 checksum
+of the resulting 48 bytes.  The MD5 output is returned as 16 bytes in
+a SSH_CMSG_AUTH_RSA_RESPONSE message.  (MD5 is used to deter chosen
+plaintext attacks against RSA; the session id binds it to a specific
+session).
+
+The server verifies that the MD5 of the decrypted challenge returned by
+the client matches that of the original value, and sends SSH_SMSG_SUCCESS if
+so.  Otherwise it sends SSH_SMSG_FAILURE and refuses the
+authentication attempt.
+
+This authentication method trusts the client side machine in that root
+on that machine can pretend to be any user on that machine.
+Additionally, it trusts the client host key.  The name and/or IP
+address of the client host is only used to select the public host key.
+The same host name is used when scanning .rhosts or /etc/hosts.equiv
+and when selecting the host key.  It would in principle be possible to
+eliminate the host name entirely and substitute it directly by the
+host key.  IP and/or DNS [RFC1034] spoofing can only be used
+to pretend to be a host for which the attacker has the private host
+key.
+.IP SSH_AUTH_RSA
+
+The idea behind RSA authentication is that the server recognizes the
+public key offered by the client, generates a random challenge, and
+encrypts the challenge with the public key.  The client must then
+prove that it has the corresponding private key by decrypting the
+challenge.
+
+The client sends SSH_CMSG_AUTH_RSA with public key modulus (n) as an
+argument.
+
+The server may respond immediately with SSH_SMSG_FAILURE if it does
+not permit authentication with this key.  Otherwise it generates a
+challenge, encrypts it using the user's public key (stored on the
+server and identified using the modulus), and sends
+SSH_SMSG_AUTH_RSA_CHALLENGE with the challenge (mp-int) as an
+argument.
+
+The challenge is 32 8-bit random bytes (256 bits).  When encrypted,
+the highest (partial) byte is left as zero, the next byte contains the
+value 2, the following are non-zero random bytes, followed by a zero
+byte, and the challenge put in the remaining bytes.  This is then
+encrypted with the public key.  (The padding and encryption algorithm
+is the same as that used for the session key.)
+
+The client decrypts the challenge using its private key, concatenates
+it with the session id, and computes an MD5 checksum of the resulting
+48 bytes.  The MD5 output is returned as 16 bytes in a
+SSH_CMSG_AUTH_RSA_RESPONSE message.  (Note that the MD5 is necessary
+to avoid chosen plaintext attacks against RSA; the session id binds it
+to a specific session.)
+
+The server verifies that the MD5 of the decrypted challenge returned
+by the client matches that of the original value, and sends
+SSH_SMSG_SUCCESS if so.  Otherwise it sends SSH_SMSG_FAILURE and
+refuses the authentication attempt.
+
+This authentication method does not trust the remote host, the
+network, name services, or anything else.  Authentication is based
+solely on the possession of the private identification keys.  Anyone
+in possession of the private keys can log in, but nobody else.
+
+The server may have additional requirements for a successful
+authentiation.  For example, to limit damage due to a compromised RSA
+key, a server might restrict access to a limited set of hosts.
+.IP SSH_AUTH_PASSWORD
+
+The client sends a SSH_CMSG_AUTH_PASSWORD message with the plain text
+password.  (Note that even though the password is plain text inside
+the message, it is normally encrypted by the packet mechanism.)
+
+The server verifies the password, and sends SSH_SMSG_SUCCESS if
+authentication was accepted and SSH_SMSG_FAILURE otherwise.
+
+Note that the password is read from the user by the client; the user
+never interacts with a login program.
+
+This authentication method does not trust the remote host, the
+network, name services or anything else.  Authentication is based
+solely on the possession of the password.  Anyone in possession of the
+password can log in, but nobody else.
+.RT
+
+.ti 0
+Preparatory Operations
+
+After successful authentication, the server waits for a request from
+the client, processes the request, and responds with SSH_SMSG_SUCCESS
+whenever a request has been successfully processed.  If it receives a
+message that it does not recognize or it fails to honor a request, it
+returns SSH_SMSG_FAILURE.  It is expected that new message types might
+be added to this phase in future.
+
+The following messages are currently defined for this phase.
+.IP SSH_CMSG_REQUEST_COMPRESSION
+Requests that compression be enabled for this session.  A
+gzip-compatible compression level (1-9) is passed as an argument.
+.IP SSH_CMSG_REQUEST_PTY
+Requests that a pseudo terminal device be allocated for this session.
+The user terminal type and terminal modes are supplied as arguments.
+.IP SSH_CMSG_X11_REQUEST_FORWARDING
+Requests forwarding of X11 connections from the remote machine to the
+local machine over the secure channel.  Causes an internet-domain
+socket to be allocated and the DISPLAY variable to be set on the server.
+X11 authentication data is automatically passed to the server, and the
+client may implement spoofing of authentication data for added
+security.  The authentication data is passed as arguments.
+.IP SSH_CMSG_PORT_FORWARD_REQUEST
+Requests forwarding of a TCP/IP port on the server host over the
+secure channel.  What happens is that whenever a connection is made to
+the port on the server, a connection will be made from the client end
+to the specified host/port.  Any user can forward unprivileged ports;
+only the root can forward privileged ports (as determined by
+authentication done earlier).
+.IP SSH_CMSG_AGENT_REQUEST_FORWARDING
+Requests forwarding of the connection to the authentication agent.
+.IP SSH_CMSG_EXEC_SHELL
+Starts a shell (command interpreter) for the user, and moves into
+interactive session mode.
+.IP SSH_CMSG_EXEC_CMD
+Executes the given command (actually "<shell> -c <command>" or
+equivalent) for the user, and moves into interactive session mode.
+.RT
+
+
+.ti 0
+Interactive Session and Exchange of Data
+
+During the interactive session, any data written by the shell or
+command running on the server machine is forwarded to stdin or
+stderr on the client machine, and any input available from stdin on
+the client machine is forwarded to the program on the server machine.
+
+All exchange is asynchronous; either side can send at any time, and
+there are no acknowledgements (TCP/IP already provides reliable
+transport, and the packet protocol protects against tampering or IP
+spoofing).
+
+When the client receives EOF from its standard input, it will send
+SSH_CMSG_EOF; however, this in no way terminates the exchange.  The
+exchange terminates and interactive mode is left when the server sends
+SSH_SMSG_EXITSTATUS to indicate that the client program has
+terminated.  Alternatively, either side may disconnect at any time by
+sending SSH_MSG_DISCONNECT or closing the connection.
+
+The server may send any of the following messages:
+.IP SSH_SMSG_STDOUT_DATA
+Data written to stdout by the program running on the server.  The data
+is passed as a string argument.  The client writes this data to
+stdout.
+.IP SSH_SMSG_STDERR_DATA
+Data written to stderr by the program running on the server.  The data
+is passed as a string argument.  The client writes this data to
+stderr.  (Note that if the program is running on a tty, it is not
+possible to separate stdout and stderr data, and all data will be sent
+as stdout data.)
+.IP SSH_SMSG_EXITSTATUS
+Indicates that the shell or command has exited.  Exit status is passed
+as an integer argument.  This message causes termination of the
+interactive session.
+.IP SSH_SMSG_AGENT_OPEN
+Indicates that someone on the server side is requesting a connection
+to the authentication agent.  The server-side channel number is passed
+as an argument.  The client must respond with either
+SSH_CHANNEL_OPEN_CONFIRMATION or SSH_CHANNEL_OPEN_FAILURE.
+.IP SSH_SMSG_X11_OPEN
+Indicates that a connection has been made to the X11 socket on the
+server side and should be forwarded to the real X server.  An integer
+argument indicates the channel number allocated for this connection on
+the server side.  The client should send back either
+SSH_MSG_CHANNEL_OPEN_CONFIRMATION or SSH_MSG_CHANNEL_OPEN_FAILURE with
+the same server side channel number.
+.IP SSH_MSG_PORT_OPEN
+Indicates that a connection has been made to a port on the server side
+for which forwarding has been requested.  Arguments are server side
+channel number, host name to connect to, and port to connect to.  The
+client should send back either
+SSH_MSG_CHANNEL_OPEN_CONFIRMATION or SSH_MSG_CHANNEL_OPEN_FAILURE with
+the same server side channel number.
+.IP SSH_MSG_CHANNEL_OPEN_CONFIRMATION
+This is sent by the server to indicate that it has opened a connection
+as requested in a previous message.  The first argument indicates the
+client side channel number, and the second argument is the channel number
+that the server has allocated for this connection.
+.IP SSH_MSG_CHANNEL_OPEN_FAILURE
+This is sent by the server to indicate that it failed to open a
+connection as requested in a previous message.  The client-side
+channel number is passed as an argument.  The client will close the
+descriptor associated with the channel and free the channel.
+.IP SSH_MSG_CHANNEL_DATA
+This packet contains data for a channel from the server.  The first
+argument is the client-side channel number, and the second argument (a
+string) is the data.
+.IP SSH_MSG_CHANNEL_CLOSE
+This is sent by the server to indicate that whoever was in the other
+end of the channel has closed it.  The argument is the client side channel
+number.  The client will let all buffered data in the channel to
+drain, and when ready, will close the socket, free the channel, and
+send the server a SSH_MSG_CHANNEL_CLOSE_CONFIRMATION message for the
+channel.
+.IP SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
+This is send by the server to indicate that a channel previously
+closed by the client has now been closed on the server side as well.
+The argument indicates the client channel number.  The client frees
+the channel.
+.RT
+
+The client may send any of the following messages:
+.IP SSH_CMSG_STDIN_DATA
+This is data to be sent as input to the program running on the server.
+The data is passed as a string.
+.IP SSH_CMSG_EOF
+Indicates that the client has encountered EOF while reading standard
+input.  The server will allow any buffered input data to drain, and
+will then close the input to the program.
+.IP SSH_CMSG_WINDOW_SIZE
+Indicates that window size on the client has been changed.  The server
+updates the window size of the tty and causes SIGWINCH to be sent to
+the program.  The new window size is passed as four integer arguments:
+row, col, xpixel, ypixel.
+.IP SSH_MSG_PORT_OPEN
+Indicates that a connection has been made to a port on the client side
+for which forwarding has been requested.  Arguments are client side
+channel number, host name to connect to, and port to connect to.  The
+server should send back either SSH_MSG_CHANNEL_OPEN_CONFIRMATION or
+SSH_MSG_CHANNEL_OPEN_FAILURE with the same client side channel number.
+.IP SSH_MSG_CHANNEL_OPEN_CONFIRMATION
+This is sent by the client to indicate that it has opened a connection
+as requested in a previous message.  The first argument indicates the
+server side channel number, and the second argument is the channel
+number that the client has allocated for this connection.
+.IP SSH_MSG_CHANNEL_OPEN_FAILURE
+This is sent by the client to indicate that it failed to open a
+connection as requested in a previous message.  The server side
+channel number is passed as an argument.  The server will close the
+descriptor associated with the channel and free the channel.
+.IP SSH_MSG_CHANNEL_DATA
+This packet contains data for a channel from the client.  The first
+argument is the server side channel number, and the second argument (a
+string) is the data.
+.IP SSH_MSG_CHANNEL_CLOSE
+This is sent by the client to indicate that whoever was in the other
+end of the channel has closed it.  The argument is the server channel
+number.  The server will allow buffered data to drain, and when ready,
+will close the socket, free the channel, and send the client a
+SSH_MSG_CHANNEL_CLOSE_CONFIRMATION message for the channel.
+.IP SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
+This is send by the client to indicate that a channel previously
+closed by the server has now been closed on the client side as well.
+The argument indicates the server channel number.  The server frees
+the channel.
+.RT
+
+Any unsupported messages during interactive mode cause the connection
+to be terminated with SSH_MSG_DISCONNECT and an error message.
+Compatible protocol upgrades should agree about any extensions during
+the preparation phase or earlier.
+
+
+.ti 0
+Termination of the Connection
+
+Normal termination of the connection is always initiated by the server
+by sending SSH_SMSG_EXITSTATUS after the program has exited.  The
+client responds to this message by sending SSH_CMSG_EXIT_CONFIRMATION
+and closes the socket; the server then closes the socket.  There are
+two purposes for the confirmation: some systems may lose previously
+sent data when the socket is closed, and closing the client side first
+causes any TCP/IP TIME_WAIT [RFC0793] waits to occur on the client side, not
+consuming server resources.
+
+If the program terminates due to a signal, the server will send
+SSH_MSG_DISCONNECT with an appropriate message.  If the connection is
+closed, all file descriptors to the program will be closed and the
+server will exit.  If the program runs on a tty, the kernel sends it
+the SIGHUP signal when the pty master side is closed.
+
+.ti 0
+Protocol Flags
+
+Both the server and the client pass 32 bits of protocol flags to the
+other side.  The flags are intended for compatible protocol extension;
+the server first announces which added capabilities it supports, and
+the client then sends the capabilities that it supports.
+
+The following flags are currently defined (the values are bit masks):
+.IP "1 SSH_PROTOFLAG_SCREEN_NUMBER"
+This flag can only be sent by the client.  It indicates that the X11
+forwarding requests it sends will include the screen number.
+.IP "2 SSH_PROTOFLAG_HOST_IN_FWD_OPEN"
+If both sides specify this flag, SSH_SMSG_X11_OPEN and
+SSH_MSG_PORT_OPEN messages will contain an additional field containing
+a description of the host at the other end of the connection.
+.RT
+
+.ti 0
+Detailed Description of Packet Types and Formats
+
+The supported packet types and the corresponding message numbers are
+given in the following table.  Messages with _MSG_ in their name may
+be sent by either side.  Messages with _CMSG_ are only sent by the
+client, and messages with _SMSG_ only by the server.
+
+A packet may contain additional data after the arguments specified
+below.  Any such data should be ignored by the receiver.  However, it
+is recommended that no such data be stored without good reason.  (This
+helps build compatible extensions.)
+.IP "0 SSH_MSG_NONE"
+This code is reserved.  This message type is never sent.
+.IP "1 SSH_MSG_DISCONNECT"
+.TS
+;
+l l.
+string Cause of disconnection
+.TE
+This message may be sent by either party at any time.  It causes the
+immediate disconnection of the connection.  The message is intended to
+be displayed to a human, and describes the reason for disconnection.
+.IP "2 SSH_SMSG_PUBLIC_KEY"
+.TS
+;
+l l.
+8 bytes        anti_spoofing_cookie
+32-bit int     server_key_bits
+mp-int server_key_public_exponent
+mp-int server_key_public_modulus
+32-bit int     host_key_bits
+mp-int host_key_public_exponent
+mp-int host_key_public_modulus
+32-bit int     protocol_flags
+32-bit int     supported_ciphers_mask
+32-bit int     supported_authentications_mask
+.TE
+Sent as the first message by the server.  This message gives the
+server's host key, server key, protocol flags (intended for compatible
+protocol extension), supported_ciphers_mask (which is the
+bitwise or of (1 << cipher_number), where << is the left shift
+operator, for all supported ciphers), and
+supported_authentications_mask (which is the bitwise or of (1 <<
+authentication_type) for all supported authentication types).  The
+anti_spoofing_cookie is 64 random bytes, and must be sent back
+verbatim by the client in its reply.  It is used to make IP-spoofing
+more difficult (encryption and host keys are the real defense against
+spoofing).
+.IP "3 SSH_CMSG_SESSION_KEY"
+.TS
+;
+l l.
+1 byte cipher_type (must be one of the supported values)
+8 bytes        anti_spoofing_cookie (must match data sent by the server)
+mp-int double-encrypted session key
+32-bit int     protocol_flags
+.TE
+Sent by the client as the first message in the session.  Selects the
+cipher to use, and sends the encrypted session key to the server.  The
+anti_spoofing_cookie must be the same bytes that were sent by the
+server.  Protocol_flags is intended for negotiating compatible
+protocol extensions.
+.IP "4 SSH_CMSG_USER"
+.TS
+;
+l l.
+string user login name on server
+.TE
+Sent by the client to begin authentication.  Specifies the user name
+on the server to log in as.  The server responds with SSH_SMSG_SUCCESS
+if no authentication is needed for this user, or SSH_SMSG_FAILURE if
+authentication is needed (or the user does not exist).  [Note to the
+implementator: the user name is of arbitrary size.  The implementation
+must be careful not to overflow internal buffers.]
+.IP "5 SSH_CMSG_AUTH_RHOSTS"
+.TS
+;
+l l.
+string client-side user name
+.TE
+Requests authentication using /etc/hosts.equiv and .rhosts (or
+equivalent mechanisms).  This authentication method is normally
+disabled in the server because it is not secure (but this is the
+method used by rsh and rlogin).  The server responds with
+SSH_SMSG_SUCCESS if authentication was successful, and
+SSH_SMSG_FAILURE if access was not granted.  The server should check
+that the client side port number is less than 1024 (a privileged
+port), and immediately reject authentication if it is not.  Supporting
+this authentication method is optional.  This method should normally
+not be enabled in the server because it is not safe.  (However, not
+enabling this only helps if rlogind and rshd are disabled.)
+.IP "6 SSH_CMSG_AUTH_RSA"
+.TS
+;
+l l.
+mp-int identity_public_modulus
+.TE
+Requests authentication using pure RSA authentication.  The server
+checks if the given key is permitted to log in, and if so, responds
+with SSH_SMSG_AUTH_RSA_CHALLENGE.  Otherwise, it responds with
+SSH_SMSG_FAILURE.  The client often tries several different keys in
+sequence until one supported by the server is found.  Authentication
+is accepted if the client gives the correct response to the challenge.
+The server is free to add other criteria for authentication, such as a
+requirement that the connection must come from a certain host.  Such
+additions are not visible at the protocol level.  Supporting this
+authentication method is optional but recommended.
+.IP "7 SSH_SMSG_AUTH_RSA_CHALLENGE"
+.TS
+;
+l l.
+mp-int encrypted challenge
+.TE
+Presents an RSA authentication challenge to the client.  The challenge
+is a 256-bit random value encrypted as described elsewhere in this
+document.  The client must decrypt the challenge using the RSA private
+key, compute MD5 of the challenge plus session id, and send back the
+resulting 16 bytes using SSH_CMSG_AUTH_RSA_RESPONSE.
+.IP "8 SSH_CMSG_AUTH_RSA_RESPONSE"
+.TS
+;
+l l.
+16 bytes       MD5 of decrypted challenge
+.TE
+This message is sent by the client in response to an RSA challenge.
+The MD5 checksum is returned instead of the decrypted challenge to
+deter known-plaintext attacks against the RSA key.  The server
+responds to this message with either SSH_SMSG_SUCCESS or
+SSH_SMSG_FAILURE.
+.IP "9 SSH_CMSG_AUTH_PASSWORD"
+.TS
+;
+l l.
+string plain text password
+.TE
+Requests password authentication using the given password.  Note that
+even though the password is plain text inside the packet, the whole
+packet is normally encrypted by the packet layer.  It would not be
+possible for the client to perform password encryption/hashing,
+because it cannot know which kind of encryption/hashing, if any, the
+server uses.  The server responds to this message with
+SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE.
+.IP "10 SSH_CMSG_REQUEST_PTY"
+.TS
+;
+l l.
+string TERM environment variable value (e.g. vt100)
+32-bit int     terminal height, rows (e.g., 24)
+32-bit int     terminal width, columns (e.g., 80)
+32-bit int     terminal width, pixels (0 if no graphics) (e.g., 480)
+32-bit int     terminal height, pixels (0 if no graphics) (e.g., 640)
+n bytes        tty modes encoded in binary
+.TE
+Requests a pseudo-terminal to be allocated for this command.  This
+message can be used regardless of whether the session will later
+execute the shell or a command.  If a pty has been requested with this
+message, the shell or command will run on a pty.  Otherwise it will
+communicate with the server using pipes, sockets or some other similar
+mechanism.
+
+The terminal type gives the type of the user's terminal.  In the UNIX
+environment it is passed to the shell or command in the TERM
+environment variable.
+
+The width and height values give the initial size of the user's
+terminal or window.  All values can be zero if not supported by the
+operating system.  The server will pass these values to the kernel if
+supported.
+
+Terminal modes are encoded into a byte stream in a portable format.
+The exact format is described later in this document.
+
+The server responds to the request with either SSH_SMSG_SUCCESS or
+SSH_SMSG_FAILURE.  If the server does not have the concept of pseudo
+terminals, it should return success if it is possible to execute a
+shell or a command so that it looks to the client as if it was running
+on a pseudo terminal.
+.IP "11 SSH_CMSG_WINDOW_SIZE"
+.TS
+;
+l l.
+32-bit int     terminal height, rows
+32-bit int     terminal width, columns
+32-bit int     terminal width, pixels
+32-bit int     terminal height, pixels
+.TE
+This message can only be sent by the client during the interactive
+session.  This indicates that the size of the user's window has
+changed, and provides the new size.  The server will update the
+kernel's notion of the window size, and a SIGWINCH signal or
+equivalent will be sent to the shell or command (if supported by the
+operating system).
+.IP "12 SSH_CMSG_EXEC_SHELL"
+
+(no arguments)
+
+Starts a shell (command interpreter), and enters interactive session
+mode.
+.IP "13 SSH_CMSG_EXEC_CMD"
+.TS
+;
+l l.
+string command to execute
+.TE
+Starts executing the given command, and enters interactive session
+mode.  On UNIX, the command is run as "<shell> -c <command>", where
+<shell> is the user's login shell.
+.IP "14 SSH_SMSG_SUCCESS"
+
+(no arguments)
+
+This message is sent by the server in response to the session key, a
+successful authentication request, and a successfully completed
+preparatory operation.
+.IP "15 SSH_SMSG_FAILURE"
+
+(no arguments)
+
+This message is sent by the server in response to a failed
+authentication operation to indicate that the user has not yet been
+successfully authenticated, and in response to a failed preparatory
+operation.  This is also sent in response to an authentication or
+preparatory operation request that is not recognized or supported.
+.IP "16 SSH_CMSG_STDIN_DATA"
+.TS
+;
+l l.
+string data
+.TE
+Delivers data from the client to be supplied as input to the shell or
+program running on the server side.  This message can only be used in
+the interactive session mode.  No acknowledgement is sent for this
+message.
+.IP "17 SSH_SMSG_STDOUT_DATA"
+.TS
+;
+l l.
+string data
+.TE
+Delivers data from the server that was read from the standard output of
+the shell or program running on the server side.  This message can
+only be used in the interactive session mode.  No acknowledgement is
+sent for this message.
+.IP "18 SSH_SMSG_STDERR_DATA"
+.TS
+;
+l l.
+string data
+.TE
+Delivers data from the server that was read from the standard error of
+the shell or program running on the server side.  This message can
+only be used in the interactive session mode.  No acknowledgement is
+sent for this message.
+.IP "19 SSH_CMSG_EOF"
+
+(no arguments)
+
+This message is sent by the client to indicate that EOF has been
+reached on the input.  Upon receiving this message, and after all
+buffered input data has been sent to the shell or program, the server
+will close the input file descriptor to the program.  This message can
+only be used in the interactive session mode.  No acknowledgement is
+sent for this message.
+.IP "20 SSH_SMSG_EXITSTATUS"
+.TS
+;
+l l.
+32-bit int     exit status of the command
+.TE
+Returns the exit status of the shell or program after it has exited.
+The client should respond with SSH_CMSG_EXIT_CONFIRMATION when it has
+received this message.  This will be the last message sent by the
+server.  If the program being executed dies with a signal instead of
+exiting normally, the server should terminate the session with
+SSH_MSG_DISCONNECT (which can be used to pass a human-readable string
+indicating that the program died due to a signal) instead of using
+this message.
+.IP "21 SSH_MSG_CHANNEL_OPEN_CONFIRMATION"
+.TS
+;
+l l.
+32-bit int     remote_channel
+32-bit int     local_channel
+.TE
+This is sent in response to any channel open request if the channel
+has been successfully opened.  Remote_channel is the channel number
+received in the initial open request; local_channel is the channel
+number the side sending this message has allocated for the channel.
+Data can be transmitted on the channel after this message.
+.IP "22 SSH_MSG_CHANNEL_OPEN_FAILURE"
+.TS
+;
+l l.
+32-bit int     remote_channel
+.TE
+This message indicates that an earlier channel open request by the
+other side has failed or has been denied.  Remote_channel is the
+channel number given in the original request.
+.IP "23 SSH_MSG_CHANNEL_DATA"
+.TS
+;
+l l.
+32-bit int     remote_channel
+string data
+.TE
+Data is transmitted in a channel in these messages.  A channel is
+bidirectional, and both sides can send these messages.  There is no
+acknowledgement for these messages.  It is possible that either side
+receives these messages after it has sent SSH_MSG_CHANNEL_CLOSE for
+the channel.  These messages cannot be received after the party has
+sent or received SSH_MSG_CHANNEL_CLOSE_CONFIRMATION.
+.IP "24 SSH_MSG_CHANNEL_CLOSE"
+.TS
+;
+l l.
+32-bit int     remote_channel
+.TE
+When a channel is closed at one end of the connection, that side sends
+this message.  Upon receiving this message, the channel should be
+closed.  When this message is received, if the channel is already
+closed (the receiving side has sent this message for the same channel
+earlier), the channel is freed and no further action is taken;
+otherwise the channel is freed and SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
+is sent in response.  (It is possible that the channel is closed
+simultaneously at both ends.)
+.IP "25 SSH_MSG_CHANNEL_CLOSE_CONFIRMATION"
+.TS
+;
+l l.
+32-bit int     remote_channel
+.TE
+This message is sent in response to SSH_MSG_CHANNEL_CLOSE unless the
+channel was already closed.  When this message is sent or received,
+the channel is freed.
+.IP "26 (OBSOLETED; was unix-domain X11 forwarding)
+.IP "27 SSH_SMSG_X11_OPEN"
+.TS
+;
+l l.
+32-bit int     local_channel
+string originator_string (see below)
+.TE
+This message can be sent by the server during the interactive session
+mode to indicate that a client has connected the fake X server.
+Local_channel is the channel number that the server has allocated for
+the connection.  The client should try to open a connection to the
+real X server, and respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION or
+SSH_MSG_CHANNEL_OPEN_FAILURE.
+
+The field originator_string is present if both sides
+specified SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags.  It
+contains a description of the host originating the connection.
+.IP "28 SSH_CMSG_PORT_FORWARD_REQUEST"
+.TS
+;
+l l.
+32-bit int     server_port
+string host_to_connect
+32-bit int     port_to_connect
+.TE
+Sent by the client in the preparatory phase, this message requests
+that server_port on the server machine be forwarded over the secure
+channel to the client machine, and from there to the specified host
+and port.  The server should start listening on the port, and send
+SSH_MSG_PORT_OPEN whenever a connection is made to it.  Supporting
+this message is optional, and the server is free to reject any forward
+request.  For example, it is highly recommended that unless the user
+has been authenticated as root, forwarding any privileged port numbers
+(below 1024) is denied.
+.IP "29 SSH_MSG_PORT_OPEN"
+.TS
+;
+l l.
+32-bit int     local_channel
+string host_name
+32-bit int     port
+string originator_string (see below)
+.TE
+Sent by either party in interactive session mode, this message
+indicates that a connection has been opened to a forwarded TCP/IP
+port.  Local_channel is the channel number that the sending party has
+allocated for the connection.  Host_name is the host the connection
+should be be forwarded to, and the port is the port on that host to
+connect.  The receiving party should open the connection, and respond
+with SSH_MSG_CHANNEL_OPEN_CONFIRMATION or
+SSH_MSG_CHANNEL_OPEN_FAILURE.  It is recommended that the receiving
+side check the host_name and port for validity to avoid compromising
+local security by compromised remote side software.  Particularly, it
+is recommended that the client permit connections only to those ports
+for which it has requested forwarding with SSH_CMSG_PORT_FORWARD_REQUEST.
+
+The field originator_string is present if both sides
+specified SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags.  It
+contains a description of the host originating the connection.
+.IP "30 SSH_CMSG_AGENT_REQUEST_FORWARDING"
+
+(no arguments)
+
+Requests that the connection to the authentication agent be forwarded
+over the secure channel.  The method used by clients to contact the
+authentication agent within each machine is implementation and machine
+dependent.  If the server accepts this request, it should arrange that
+any clients run from this session will actually contact the server
+program when they try to contact the authentication agent.  The server
+should then send a SSH_SMSG_AGENT_OPEN to open a channel to the agent,
+and the client should forward the connection to the real
+authentication agent.  Supporting this message is optional.
+.IP "31 SSH_SMSG_AGENT_OPEN"
+.TS
+;
+l l.
+32-bit int     local_channel
+.TE
+Sent by the server in interactive session mode, this message requests
+opening a channel to the authentication agent.  The client should open
+a channel, and respond with either SSH_MSG_CHANNEL_OPEN_CONFIRMATION
+or SSH_MSG_CHANNEL_OPEN_FAILURE.
+.IP "32 SSH_MSG_IGNORE"
+.TS
+;
+l l.
+string data
+.TE
+Either party may send this message at any time.  This message, and the
+argument string, is silently ignored.  This message might be used in
+some implementations to make traffic analysis more difficult.  This
+message is not currently sent by the implementation, but all
+implementations are required to recognize and ignore it.
+.IP "33 SSH_CMSG_EXIT_CONFIRMATION"
+
+(no arguments)
+
+Sent by the client in response to SSH_SMSG_EXITSTATUS.  This is the
+last message sent by the client.
+.IP "34 SSH_CMSG_X11_REQUEST_FORWARDING"
+.TS
+;
+l l.
+string x11_authentication_protocol
+string x11_authentication_data
+32-bit int     screen number (if SSH_PROTOFLAG_SCREEN_NUMBER)
+.TE
+Sent by the client during the preparatory phase, this message requests
+that the server create a fake X11 display and set the DISPLAY
+environment variable accordingly.  An internet-domain display is
+preferable.  The given authentication protocol and the associated data
+should be recorded by the server so that it is used as authentication
+on connections (e.g., in .Xauthority).  The authentication protocol
+must be one of the supported X11 authentication protocols, e.g.,
+"MIT-MAGIC-COOKIE-1".  Authentication data must be a lowercase hex
+string of even length.  Its interpretation is protocol dependent.
+The data is in a format that can be used with e.g. the xauth program.
+Supporting this message is optional.
+
+The client is permitted (and recommended) to generate fake
+authentication information and send fake information to the server.
+This way, a corrupt server will not have access to the user's terminal
+after the connection has terminated.  The correct authorization codes
+will also not be left hanging around in files on the server (many
+users keep the same X session for months, thus protecting the
+authorization data becomes important).
+
+X11 authentication spoofing works by initially sending fake (random)
+authentication data to the server, and interpreting the first packet
+sent by the X11 client after the connection has been opened.  The
+first packet contains the client's authentication.  If the packet
+contains the correct fake data, it is replaced by the client by the
+correct authentication data, and then sent to the X server.
+.IP "35 SSH_CMSG_AUTH_RHOSTS_RSA"
+.TS
+;
+l l.
+string clint-side user name
+32-bit int     client_host_key_bits
+mp-int client_host_key_public_exponent
+mp-int client_host_key_public_modulus
+.TE
+Requests authentication using /etc/hosts.equiv and .rhosts (or
+equivalent) together with RSA host authentication.  The server should
+check that the client side port number is less than 1024 (a privileged
+port), and immediately reject authentication if it is not.  The server
+responds with SSH_SMSG_FAILURE or SSH_SMSG_AUTH_RSA_CHALLENGE.  The
+client must respond to the challenge with the proper
+SSH_CMSG_AUTH_RSA_RESPONSE.  The server then responds with success if
+access was granted, or failure if the client gave a wrong response.
+Supporting this authentication method is optional but recommended in
+most environments.
+.IP "36 SSH_MSG_DEBUG"
+.TS
+;
+l l.
+string debugging message sent to the other side
+.TE
+This message may be sent by either party at any time.  It is used to
+send debugging messages that may be informative to the user in
+solving various problems.  For example, if authentication fails
+because of some configuration error (e.g., incorrect permissions for
+some file), it can be very helpful for the user to make the cause of
+failure available.  On the other hand, one should not make too much
+information available for security reasons.  It is recommended that
+the client provides an option to display the debugging information
+sent by the sender (the user probably does not want to see it by default).
+The server can log debugging data sent by the client (if any).  Either
+party is free to ignore any received debugging data.  Every
+implementation must be able to receive this message, but no
+implementation is required to send these.
+.IP "37 SSH_CMSG_REQUEST_COMPRESSION"
+.TS
+;
+l l.
+32-bit int     gzip compression level (1-9)
+.TE
+This message can be sent by the client in the preparatory operations
+phase.  The server responds with SSH_SMSG_FAILURE if it does not
+support compression or does not want to compress; it responds with
+SSH_SMSG_SUCCESS if it accepted the compression request.  In the
+latter case the response to this packet will still be uncompressed,
+but all further packets in either direction will be compressed by gzip.
+.RT
+
+
+.ti 0
+Encoding of Terminal Modes
+
+Terminal modes (as passed in SSH_CMSG_REQUEST_PTY) are encoded into a
+byte stream.  It is intended that the coding be portable across
+different environments.
+
+The tty mode description is a stream of bytes.  The stream consists of
+opcode-argument pairs.  It is terminated by opcode TTY_OP_END (0).
+Opcodes 1-127 have one-byte arguments.  Opcodes 128-159 have 32-bit
+integer arguments (stored msb first).  Opcodes 160-255 are not yet
+defined, and cause parsing to stop (they should only be used after any
+other data).
+
+The client puts in the stream any modes it knows about, and the server
+ignores any modes it does not know about.  This allows some degree of
+machine-independence, at least between systems that use a POSIX-like
+[POSIX] tty interface.  The protocol can support other systems as
+well, but the client may need to fill reasonable values for a number
+of parameters so the server pty gets set to a reasonable mode (the
+server leaves all unspecified mode bits in their default values, and
+only some combinations make sense).
+
+The following opcodes have been defined.  The naming of opcodes mostly
+follows the POSIX terminal mode flags.
+.IP "0 TTY_OP_END"
+Indicates end of options.
+.IP "1 VINTR"
+Interrupt character; 255 if none.  Similarly for the other characters.
+Not all of these characters are supported on all systems.
+.IP "2 VQUIT"
+The quit character (sends SIGQUIT signal on UNIX systems).
+.IP "3 VERASE"
+Erase the character to left of the cursor.
+.IP "4 VKILL"
+Kill the current input line.
+.IP "5 VEOF "
+End-of-file character (sends EOF from the terminal).
+.IP "6 VEOL "
+End-of-line character in addition to carriage return and/or linefeed.
+.IP "7 VEOL2"
+Additional end-of-line character.
+.IP "8 VSTART"
+Continues paused output (normally ^Q).
+.IP "9 VSTOP"
+Pauses output (^S).
+.IP "10 VSUSP"
+Suspends the current program.
+.IP "11 VDSUSP"
+Another suspend character.
+.IP "12 VREPRINT"
+Reprints the current input line.
+.IP "13 VWERASE"
+Erases a word left of cursor.
+.IP "14 VLNEXT"
+More special input characters; these are probably not supported on
+most systems.
+.IP "15 VFLUSH"
+.IP "16 VSWTCH"
+.IP "17 VSTATUS"
+.IP "18 VDISCARD"
+
+.IP "30 IGNPAR"
+The ignore parity flag.  The next byte should be 0 if this flag is not
+set, and 1 if it is set.
+.IP "31 PARMRK"
+More flags.  The exact definitions can be found in the POSIX standard.
+.IP "32 INPCK"
+.IP "33 ISTRIP"
+.IP "34 INLCR"
+.IP "35 IGNCR"
+.IP "36 ICRNL"
+.IP "37 IUCLC"
+.IP "38 IXON"
+.IP "39 IXANY"
+.IP "40 IXOFF"
+.IP "41 IMAXBEL"
+
+.IP "50 ISIG"
+.IP "51 ICANON"
+.IP "52 XCASE"
+.IP "53 ECHO"
+.IP "54 ECHOE"
+.IP "55 ECHOK"
+.IP "56 ECHONL"
+.IP "57 NOFLSH"
+.IP "58 TOSTOP"
+.IP "59 IEXTEN"
+.IP "60 ECHOCTL"
+.IP "61 ECHOKE"
+.IP "62 PENDIN"
+
+.IP "70 OPOST"
+.IP "71 OLCUC"
+.IP "72 ONLCR"
+.IP "73 OCRNL"
+.IP "74 ONOCR"
+.IP "75 ONLRET"
+
+.IP "90 CS7"
+.IP "91 CS8"
+.IP "92 PARENB"
+.IP "93 PARODD"
+
+.IP "192 TTY_OP_ISPEED"
+Specifies the input baud rate in bits per second.
+.IP "193 TTY_OP_OSPEED"
+Specifies the output baud rate in bits per second.
+.RT
+
+
+.ti 0
+The Authentication Agent Protocol
+
+The authentication agent is a program that can be used to hold RSA
+authentication keys for the user (in future, it might hold data for
+other authentication types as well).  An authorized program can send
+requests to the agent to generate a proper response to an RSA
+challenge.  How the connection is made to the agent (or its
+representative) inside a host and how access control is done inside a
+host is implementation-dependent; however, how it is forwarded and how
+one interacts with it is specified in this protocol.  The connection
+to the agent is normally automatically forwarded over the secure
+channel.
+
+A program that wishes to use the agent first opens a connection to its
+local representative (typically, the agent itself or an SSH server).
+It then writes a request to the connection, and waits for response.
+It is recommended that at least five minutes of timeout are provided
+waiting for the agent to respond to an authentication challenge (this
+gives sufficient time for the user to cut-and-paste the challenge to a
+separate machine, perform the computation there, and cut-and-paste the
+result back if so desired).
+
+Messages sent to and by the agent are in the following format:
+.TS
+;
+l l.
+4 bytes        Length, msb first.  Does not include length itself.
+1 byte Packet type.  The value 255 is reserved for future extensions.
+data   Any data, depending on packet type.  Encoding as in the ssh packet
+protocol.
+.TE
+
+The following message types are currently defined:
+.IP "1 SSH_AGENTC_REQUEST_RSA_IDENTITIES"
+
+(no arguments)
+
+Requests the agent to send a list of all RSA keys for which it can
+answer a challenge.
+.IP "2 SSH_AGENT_RSA_IDENTITIES_ANSWER"
+.TS
+;
+l l.
+32-bit int     howmany
+howmany times:
+32-bit int     bits
+mp-int public exponent
+mp-int public modulus
+string comment
+.TE
+The agent sends this message in response to the to
+SSH_AGENTC_REQUEST_RSA_IDENTITIES.  The answer lists all RSA keys for
+which the agent can answer a challenge.  The comment field is intended
+to help identify each key; it may be printed by an application to
+indicate which key is being used.  If the agent is not holding any
+keys, howmany will be zero.
+.IP "3 SSH_AGENTC_RSA_CHALLENGE
+.TS
+;
+l l.
+32-bit int     bits
+mp-int public exponent
+mp-int public modulus
+mp-int challenge
+16 bytes       session_id
+32-bit int     response_type
+.TE
+Requests RSA decryption of random challenge to authenticate the other
+side.  The challenge will be decrypted with the RSA private key
+corresponding to the given public key.
+
+The decrypted challenge must contain a zero in the highest (partial)
+byte, 2 in the next byte, followed by non-zero random bytes, a zero
+byte, and then the real challenge value in the lowermost bytes.  The
+real challenge must be 32 8-bit bytes (256 bits).
+
+Response_type indicates the format of the response to be returned.
+Currently the only supported value is 1, which means to compute MD5 of
+the real challenge plus session id, and return the resulting 16 bytes
+in a SSH_AGENT_RSA_RESPONSE message.
+.IP "4 SSH_AGENT_RSA_RESPONSE"
+.TS
+;
+l l.
+16 bytes       MD5 of decrypted challenge
+.TE
+Answers an RSA authentication challenge.  The response is 16 bytes:
+the MD5 checksum of the 32-byte challenge.
+.IP "5 SSH_AGENT_FAILURE"
+
+(no arguments)
+
+This message is sent whenever the agent fails to answer a request
+properly.  For example, if the agent cannot answer a challenge (e.g.,
+no longer has the proper key), it can respond with this.  The agent
+also responds with this message if it receives a message it does not
+recognize.
+.IP "6 SSH_AGENT_SUCCESS"
+
+(no arguments)
+
+This message is sent by the agent as a response to certain requests
+that do not otherwise cause a message be sent.  Currently, this is
+only sent in response to SSH_AGENTC_ADD_RSA_IDENTITY and
+SSH_AGENTC_REMOVE_RSA_IDENTITY.
+.IP "7 SSH_AGENTC_ADD_RSA_IDENTITY"
+.TS
+;
+l l.
+32-bit int     bits
+mp-int public modulus
+mp-int public exponent
+mp-int private exponent
+mp-int multiplicative inverse of p mod q
+mp-int p
+mp-int q
+string comment
+.TE
+Registers an RSA key with the agent.  After this request, the agent can
+use this RSA key to answer requests.  The agent responds with
+SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE.
+.IP "8 SSH_AGENT_REMOVE_RSA_IDENTITY"
+.TS
+;
+l l.
+32-bit int     bits
+mp-int public exponent
+mp-int public modulus
+.TE
+Removes an RSA key from the agent.  The agent will no longer accept
+challenges for this key and will not list it as a supported identity.
+The agent responds with SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE.
+.RT
+
+If the agent receives a message that it does not understand, it
+responds with SSH_AGENT_FAILURE.  This permits compatible future
+extensions.
+
+It is possible that several clients have a connection open to the
+authentication agent simultaneously.  Each client will use a separate
+connection (thus, any SSH connection can have multiple agent
+connections active simultaneously).
+
+
+.ti 0
+References
+
+.IP "[DES] "
+FIPS PUB 46-1: Data Encryption Standard.  National Bureau of
+Standards, January 1988.  FIPS PUB 81: DES Modes of Operation.
+National Bureau of Standards, December 1980.  Bruce Schneier: Applied
+Cryptography.  John Wiley & Sons, 1994.  J. Seberry and J. Pieprzyk:
+Cryptography: An Introduction to Computer Security.  Prentice-Hall,
+1989.
+.IP "[GZIP] "
+The GNU GZIP program; available for anonymous ftp at prep.ai.mit.edu.
+Please let me know if you know a paper describing the algorithm.
+.IP "[IDEA] "
+Xuejia Lai: On the Design and Security of Block Ciphers, ETH Series in
+Information Processing, vol. 1, Hartung-Gorre Verlag, Konstanz,
+Switzerland, 1992.  Bruce Schneier: Applied Cryptography, John Wiley &
+Sons, 1994.  See also the following patents: PCT/CH91/00117, EP 0 482
+154 B1, US Pat. 5,214,703.
+.IP [PKCS#1]
+PKCS #1: RSA Encryption Standard.  Version 1.5, RSA Laboratories,
+November 1993.  Available for anonymous ftp at ftp.rsa.com.
+.IP [POSIX]
+Portable Operating System Interface (POSIX) - Part 1: Application
+Program Interface (API) [C language], ISO/IEC 9945-1, IEEE Std 1003.1,
+1990.
+.IP [RFC0791]
+J. Postel: Internet Protocol, RFC 791, USC/ISI, September 1981.
+.IP [RFC0793]
+J. Postel: Transmission Control Protocol, RFC 793, USC/ISI, September
+1981.
+.IP [RFC1034]
+P. Mockapetris: Domain Names - Concepts and Facilities, RFC 1034,
+USC/ISI, November 1987.
+.IP [RFC1282]
+B. Kantor: BSD Rlogin, RFC 1258, UCSD, December 1991.
+.IP "[RSA] "
+Bruce Schneier: Applied Cryptography.  John Wiley & Sons, 1994.  See
+also R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic
+Communications System and Method.  US Patent 4,405,829, 1983.
+.IP "[X11] "
+R. Scheifler: X Window System Protocol, X Consortium Standard, Version
+11, Release 6.  Massachusetts Institute of Technology, Laboratory of
+Computer Science, 1994.
+.RT
+
+
+.ti 0
+Security Considerations
+
+This protocol deals with the very issue of user authentication and
+security.
+
+First of all, as an implementation issue, the server program will have
+to run as root (or equivalent) on the server machine.  This is because
+the server program will need be able to change to an arbitrary user
+id.  The server must also be able to create a privileged TCP/IP port.
+
+The client program will need to run as root if any variant of .rhosts
+authentication is to be used.  This is because the client program will
+need to create a privileged port.  The client host key is also usually
+stored in a file which is readable by root only.  The client needs the
+host key in .rhosts authentication only.  Root privileges can be
+dropped as soon as the privileged port has been created and the host
+key has been read.
+
+The SSH protocol offers major security advantages over existing telnet
+and rlogin protocols.
+.IP o
+IP spoofing is restricted to closing a connection (by encryption, host
+keys, and the special random cookie).  If encryption is not used, IP
+spoofing is possible for those who can hear packets going out from the
+server.
+.IP o
+DNS spoofing is made ineffective (by host keys).
+.IP o
+Routing spoofing is made ineffective (by host keys).
+.IP o
+All data is encrypted with strong algorithms to make eavesdropping as
+difficult as possible.  This includes encrypting any authentication
+information such as passwords.  The information for decrypting session
+keys is destroyed every hour.
+.IP o
+Strong authentication methods: .rhosts combined with RSA host
+authentication, and pure RSA authentication.
+.IP o
+X11 connections and arbitrary TCP/IP ports can be forwarded securely.
+.IP o
+Man-in-the-middle attacks are deterred by using the server host key to
+encrypt the session key.
+.IP o
+Trojan horses to catch a password by routing manipulation are deterred
+by checking that the host key of the server machine matches that
+stored on the client host.
+.RT
+
+The security of SSH against man-in-the-middle attacks and the security
+of the new form of .rhosts authentication, as well as server host
+validation, depends on the integrity of the host key and the files
+containing known host keys.
+
+The host key is normally stored in a root-readable file.  If the host
+key is compromised, it permits attackers to use IP, DNS and routing
+spoofing as with current rlogin and rsh.  It should never be any worse
+than the current situation.
+
+The files containing known host keys are not sensitive.  However, if an
+attacker gets to modify the known host key files, it has the same
+consequences as a compromised host key, because the attacker can then
+change the recorded host key.
+
+The security improvements obtained by this protocol for X11 are of
+particular significance.  Previously, there has been no way to protect
+data communicated between an X server and a client running on a remote
+machine.  By creating a fake display on the server, and forwarding all
+X11 requests over the secure channel, SSH can be used to run any X11
+applications securely without any cooperation with the vendors of the
+X server or the application.
+
+Finally, the security of this program relies on the strength of the
+underlying cryptographic algorithms.  The RSA algorithm is used for
+authentication key exchange.  It is widely believed to be secure.  Of
+the algorithms used to encrypt the session, DES has a rather small key
+these days, probably permitting governments and organized criminals to
+break it in very short time with specialized hardware.  3DES is
+probably safe (but slower).  IDEA is widely believed to be secure.
+People have varying degrees of confidence in the other algorithms.
+This program is not secure if used with no encryption at all.
+
+
+.ti 0
+Additional Information
+
+Additional information (especially on the implementation and mailing
+lists) is available via WWW at http://www.cs.hut.fi/ssh.
+
+Comments should be sent to Tatu Ylonen <ylo@cs.hut.fi> or the SSH
+Mailing List <ssh@clinet.fi>.
+
+.ti 0
+Author's Address
+
+.TS
+;
+l.
+Tatu Ylonen
+Helsinki University of Technology
+Otakaari 1
+FIN-02150 Espoo, Finland
+
+Phone: +358-0-451-3374
+Fax: +358-0-451-3293
+EMail: ylo@cs.hut.fi
+.TE
diff --git a/openssh/TODO b/openssh/TODO
new file mode 100644 (file)
index 0000000..3c89852
--- /dev/null
@@ -0,0 +1,86 @@
+Programming:
+- Grep for 'XXX' comments and fix
+
+- Link order is incorrect for some systems using Kerberos 4 and AFS. Result
+  is multiple inclusion of DES symbols. Holger Trapp 
+  <holger.trapp@hrz.tu-chemnitz.de> reports that changing the configure
+  generated link order from:
+       -lresolv -lkrb -lz -lnsl  -lutil -lkafs -lkrb -ldes -lcrypto
+  to:
+       -lresolv -lkrb -lz -lnsl  -lutil -lcrypto -lkafs -lkrb -ldes
+  fixing the problem.
+
+- Write a test program that calls stat() to search for EGD/PRNGd socket
+  rather than use the (non-portable) "test -S". 
+
+- Replacement for setproctitle() - HP-UX support only currently
+
+- Handle changing passwords for the non-PAM expired password case
+
+- Improve PAM support (a pam_lastlog module will cause sshd to exit)
+  and maybe support alternate forms of authenications like OPIE via
+  pam?
+
+- Rework PAM ChallengeResponseAuthentication
+ - Use kbdint request packet with 0 prompts for informational messages
+ - Use different PAM service name for kbdint vs regular auth (suggest from
+   Solar Designer)
+ - Ability to select which ChallengeResponseAuthentications may be used
+   and order to try them in e.g. "ChallengeResponseAuthentication skey, pam"
+
+- Complete Tru64 SIA support
+ - It looks like we could merge it into the password auth code to cut down
+   on diff size. Maybe PAM password auth too?
+
+- Finish integrating kernel-level auditing code for IRIX and SOLARIS
+  (Gilbert.r.loomis@saic.com)
+
+- sftp-server:  Rework to step down to 32bit ints if the platform
+  lacks 'long long' == 64bit (Notable SCO w/ SCO compiler)
+
+- Linux hangs for 20 seconds when you do "sleep 20&exit".  All current
+  solutions break scp or leaves processes hanging around after the ssh
+  connection has ended.  It seems to be linked to two things.  One
+  select() under Linux is not as nice as others, and two the children
+  of the shell are not killed on exiting the shell. Redhat have an excellent
+  description of this in their RPM package.
+
+- Build an automated test suite
+
+- 64-bit builds on HP-UX 11.X (stevesk@pobox.com):
+  - utmp/wtmp get corrupted (something in loginrec?)
+  - can't build with PAM (no 64-bit libpam yet)
+
+Documentation:
+- More and better
+
+- Install FAQ?
+
+- General FAQ on S/Key, TIS, RSA, RSA2, DSA, etc and suggestions on when it
+  would be best to use them.  
+
+- Create a Documentation/ directory?
+
+Clean up configure/makefiles:
+- Clean up configure.ac - There are a few double #defined variables
+  left to do.  HAVE_LOGIN is one of them.  Consider NOT looking for
+  information in wtmpx or utmpx or any of that stuff if it's not detected
+  from the start
+
+- Fails to compile when cross compile.
+  (vinschen@redhat.com)
+
+- Replace the whole u_intXX_t evilness in acconfig.h with something better???
+
+- Consider splitting the u_intXX_t test for sys/bitype.h  into seperate test
+  to allow people to (right/wrongfully) link against Bind directly.
+
+Packaging:
+- Solaris: Update packaging scripts and build new sysv startup scripts
+  Ideally the package metadata should be generated by autoconf.
+  (gilbert.r.loomis@saic.com)
+
+- HP-UX: Provide DEPOT package scripts.
+  (gilbert.r.loomis@saic.com)
+
+$Id$
diff --git a/openssh/WARNING.RNG b/openssh/WARNING.RNG
new file mode 100644 (file)
index 0000000..1b9137e
--- /dev/null
@@ -0,0 +1,83 @@
+This document contains a description of portable OpenSSH's random
+number collection code. An alternate reading of this text could
+well be titled "Why I should pressure my system vendor to supply
+/dev/random in their OS".
+
+Why is this important? OpenSSH depends on good, unpredictable numbers
+for generating keys, performing digital signatures and forming
+cryptographic challenges. If the random numbers that it uses are
+predictable, then the strength of the whole system is compromised.
+
+A particularly pernicious problem arises with DSA keys (used by the
+ssh2 protocol). Performing a DSA signature (which is required for
+authentication), entails the use of a 160 bit random number.  If an
+attacker can predict this number, then they can deduce your *private*
+key and impersonate you or your hosts.
+
+If you are using the builtin random number support (configure will
+tell you if this is the case), then read this document in its entirety.
+Alternately, you can use Lutz Jaenicke's PRNGd - a small daemon which
+collects random numbers and makes them available by a socket.
+
+Please also request that your OS vendor provides a kernel-based random
+number collector (/dev/random) in future versions of your operating
+systems by default.
+
+On to the description...
+
+The portable OpenSSH contains random number collection support for
+systems which lack a kernel entropy pool (/dev/random).
+
+This collector operates by executing the programs listed in
+($etcdir)/ssh_prng_cmds, reading their output and adding it to the
+PRNG supplied by OpenSSL (which is hash-based). It also stirs in the
+output of several system calls and timings from the execution of the
+programs that it runs.
+
+The ssh_prng_cmds file also specifies a 'rate' for each program. This
+represents the number of bits of randomness per byte of output from
+the specified program.
+
+The random number code will also read and save a seed file to
+~/.ssh/prng_seed. This contents of this file are added to the random
+number generator at startup. The goal here is to maintain as much 
+randomness between sessions as possible.
+
+The entropy collection code has two main problems:
+
+1. It is slow.
+
+Executing each program in the list can take a large amount of time,   
+especially on slower machines. Additionally some program can take a   
+disproportionate time to execute.                                     
+
+This can be tuned by the administrator. To debug the entropy
+collection is great detail, turn on full debugging ("ssh -v -v -v" or
+"sshd -d -d -d"). This will list each program as it is executed, how
+long it took to execute, its exit status and whether and how much data
+it generated. You can the find the culprit programs which are causing
+the real slow-downs.
+
+The entropy collector will timeout programs which take too long
+to execute, the actual timeout used can be adjusted with the
+--with-entropy-timeout configure option. OpenSSH will not try to
+re-execute programs which have not been found, have had a non-zero
+exit status or have timed out more than a couple of times.
+
+2. Estimating the real 'rate' of program outputs is non-trivial
+
+The shear volume of the task is problematic: there are currently
+around 50 commands in the ssh_prng_cmds list, portable OpenSSH
+supports at least 12 different OSs. That is already 600 sets of data
+to be analysed, without taking into account the numerous differences
+between versions of each OS.
+
+On top of this, the different commands can produce varying amounts of
+usable data depending on how busy the machine is, how long it has been
+up and various other factors.
+
+To make matters even more complex, some of the commands are reporting
+largely the same data as other commands (eg. the various "ps" calls).
+
+$Id$
+
diff --git a/openssh/acconfig.h b/openssh/acconfig.h
new file mode 100644 (file)
index 0000000..436d72e
--- /dev/null
@@ -0,0 +1,338 @@
+/* $Id$ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+/* Generated automatically from acconfig.h by autoheader. */
+/* Please make your changes there */
+
+@TOP@
+
+/* Define to a Set Process Title type if your system is */
+/* supported by bsd-setproctitle.c */
+#undef SPT_TYPE
+
+/* SCO workaround */
+#undef BROKEN_SYS_TERMIO_H
+#undef HAVE_BOGUS_SYS_QUEUE_H
+
+/* Define if you have SCO protected password database */
+#undef HAVE_SCO_PROTECTED_PW
+
+/* If your header files don't define LOGIN_PROGRAM, then use this (detected) */
+/* from environment and PATH */
+#undef LOGIN_PROGRAM_FALLBACK
+
+/* Define if your password has a pw_class field */
+#undef HAVE_PW_CLASS_IN_PASSWD
+
+/* Define if your password has a pw_expire field */
+#undef HAVE_PW_EXPIRE_IN_PASSWD
+
+/* Define if your password has a pw_change field */
+#undef HAVE_PW_CHANGE_IN_PASSWD
+
+/* Define if you system's inet_ntoa is busted (e.g. Irix gcc issue) */
+#undef BROKEN_INET_NTOA
+
+/* Define if your system defines sys_errlist[] */
+#undef HAVE_SYS_ERRLIST
+
+/* Define if your system defines sys_nerr */
+#undef HAVE_SYS_NERR
+
+/* Define if your system choked on IP TOS setting */
+#undef IP_TOS_IS_BROKEN
+
+/* Define if you have the getuserattr function.  */
+#undef HAVE_GETUSERATTR
+
+/* Work around problematic Linux PAM modules handling of PAM_TTY */
+#undef PAM_TTY_KLUDGE
+
+/* Use PIPES instead of a socketpair() */
+#undef USE_PIPES
+
+/* Define if your snprintf is busted */
+#undef BROKEN_SNPRINTF
+
+/* Define if you are on Cygwin */
+#undef HAVE_CYGWIN
+
+/* Define if you lack native POSIX regex and you are using PCRE */
+#undef HAVE_LIBPCRE
+
+/* Define if you have a broken realpath. */
+#undef BROKEN_REALPATH
+
+/* Define if you are on NeXT */
+#undef HAVE_NEXT
+
+/* Define if you are on NEWS-OS */
+#undef HAVE_NEWS4
+
+/* Define if you want to enable PAM support */
+#undef USE_PAM
+
+/* Define if you want to enable AIX4's authenticate function */
+#undef WITH_AIXAUTHENTICATE
+
+/* Define if you have/want arrays (cluster-wide session managment, not C arrays) */
+#undef WITH_IRIX_ARRAY
+
+/* Define if you want IRIX project management */
+#undef WITH_IRIX_PROJECT
+
+/* Define if you want IRIX audit trails */
+#undef WITH_IRIX_AUDIT
+
+/* Define if you want IRIX kernel jobs */
+#undef WITH_IRIX_JOBS
+
+/* Location of random number pool  */
+#undef RANDOM_POOL
+
+/* Location of PRNGD/EGD random number socket */
+#undef PRNGD_SOCKET
+
+/* Port number of PRNGD/EGD random number socket */
+#undef PRNGD_PORT
+
+/* Builtin PRNG command timeout */
+#undef ENTROPY_TIMEOUT_MSEC
+
+/* Define if you want to install preformatted manpages.*/
+#undef MANTYPE
+
+/* Define if your ssl headers are included with #include <openssl/header.h>  */
+#undef HAVE_OPENSSL
+
+/* Define if you are linking against RSAref.  Used only to print the right
+ * message at run-time. */
+#undef RSAREF
+
+/* struct timeval */
+#undef HAVE_STRUCT_TIMEVAL
+
+/* struct utmp and struct utmpx fields */
+#undef HAVE_HOST_IN_UTMP
+#undef HAVE_HOST_IN_UTMPX
+#undef HAVE_ADDR_IN_UTMP
+#undef HAVE_ADDR_IN_UTMPX
+#undef HAVE_ADDR_V6_IN_UTMP
+#undef HAVE_ADDR_V6_IN_UTMPX
+#undef HAVE_SYSLEN_IN_UTMPX
+#undef HAVE_PID_IN_UTMP
+#undef HAVE_TYPE_IN_UTMP
+#undef HAVE_TYPE_IN_UTMPX
+#undef HAVE_TV_IN_UTMP
+#undef HAVE_TV_IN_UTMPX
+#undef HAVE_ID_IN_UTMP
+#undef HAVE_ID_IN_UTMPX
+#undef HAVE_EXIT_IN_UTMP
+#undef HAVE_TIME_IN_UTMP
+#undef HAVE_TIME_IN_UTMPX
+
+/* Define if you don't want to use your system's login() call */
+#undef DISABLE_LOGIN
+
+/* Define if you don't want to use pututline() etc. to write [uw]tmp */
+#undef DISABLE_PUTUTLINE
+
+/* Define if you don't want to use pututxline() etc. to write [uw]tmpx */
+#undef DISABLE_PUTUTXLINE
+
+/* Define if you don't want to use lastlog */
+#undef DISABLE_LASTLOG
+
+/* Define if you don't want to use utmp */
+#undef DISABLE_UTMP
+
+/* Define if you don't want to use utmpx */
+#undef DISABLE_UTMPX
+
+/* Define if you don't want to use wtmp */
+#undef DISABLE_WTMP
+
+/* Define if you don't want to use wtmpx */
+#undef DISABLE_WTMPX
+
+/* Some systems need a utmpx entry for /bin/login to work */
+#undef LOGIN_NEEDS_UTMPX
+
+/* Some versions of /bin/login need the TERM supplied on the commandline */
+#undef LOGIN_NEEDS_TERM
+
+/* Define if you want to specify the path to your lastlog file */
+#undef CONF_LASTLOG_FILE
+
+/* Define if you want to specify the path to your utmp file */
+#undef CONF_UTMP_FILE
+
+/* Define if you want to specify the path to your wtmp file */
+#undef CONF_WTMP_FILE
+
+/* Define if you want to specify the path to your utmpx file */
+#undef CONF_UTMPX_FILE
+
+/* Define if you want to specify the path to your wtmpx file */
+#undef CONF_WTMPX_FILE
+
+/* Define if you want external askpass support */
+#undef USE_EXTERNAL_ASKPASS
+
+/* Define if libc defines __progname */
+#undef HAVE___PROGNAME
+
+/* Define if you want Kerberos 4 support */
+#undef KRB4
+
+/* Define if you want AFS support */
+#undef AFS
+
+/* Define if you want S/Key support */
+#undef SKEY
+
+/* Define if you want TCP Wrappers support */
+#undef LIBWRAP
+
+/* Define if your libraries define login() */
+#undef HAVE_LOGIN
+
+/* Define if your libraries define daemon() */
+#undef HAVE_DAEMON
+
+/* Define if your libraries define getpagesize() */
+#undef HAVE_GETPAGESIZE
+
+/* Define if xauth is found in your path */
+#undef XAUTH_PATH
+
+/* Define if rsh is found in your path */
+#undef RSH_PATH
+
+/* Define if you want to allow MD5 passwords */
+#undef HAVE_MD5_PASSWORDS
+
+/* Define if you want to disable shadow passwords */
+#undef DISABLE_SHADOW
+
+/* Define if you want to use shadow password expire field */
+#undef HAS_SHADOW_EXPIRE
+
+/* Define if you have Digital Unix Security Integration Architecture */
+#undef HAVE_OSF_SIA
+
+/* Define if you have getpwanam(3) [SunOS 4.x] */
+#undef HAVE_GETPWANAM
+
+/* Defined if in_systm.h needs to be included with netinet/ip.h (HPUX - <sigh/>) */
+#undef NEED_IN_SYSTM_H
+
+/* Define if you have an old version of PAM which takes only one argument */
+/* to pam_strerror */
+#undef HAVE_OLD_PAM
+
+/* Define if you are using Solaris-derived PAM which passes pam_messages  */
+/* to the conversation function with an extra level of indirection */
+#undef PAM_SUN_CODEBASE
+
+/* Set this to your mail directory if you don't have maillock.h */
+#undef MAIL_DIRECTORY
+
+/* Data types */
+#undef HAVE_U_INT
+#undef HAVE_INTXX_T
+#undef HAVE_U_INTXX_T
+#undef HAVE_UINTXX_T
+#undef HAVE_INT64_T
+#undef HAVE_U_INT64_T
+#undef HAVE_U_CHAR
+#undef HAVE_SIZE_T
+#undef HAVE_SSIZE_T
+#undef HAVE_CLOCK_T
+#undef HAVE_MODE_T
+#undef HAVE_PID_T
+#undef HAVE_SA_FAMILY_T
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+#undef HAVE_STRUCT_ADDRINFO
+#undef HAVE_STRUCT_IN6_ADDR
+#undef HAVE_STRUCT_SOCKADDR_IN6
+
+/* Fields in struct sockaddr_storage */
+#undef HAVE_SS_FAMILY_IN_SS
+#undef HAVE___SS_FAMILY_IN_SS
+
+/* Define if you have a regcomp() function */
+#undef HAVE_REGCOMP
+
+/* Define if you have /dev/ptmx */
+#undef HAVE_DEV_PTMX
+
+/* Define if you have /dev/ptc */
+#undef HAVE_DEV_PTS_AND_PTC
+
+/* Define if you need to use IP address instead of hostname in $DISPLAY */
+#undef IPADDR_IN_DISPLAY
+
+/* Specify default $PATH */
+#undef USER_PATH
+
+/* Specify location of ssh.pid */
+#undef _PATH_SSH_PIDDIR
+
+/* Use IPv4 for connection by default, IPv6 can still if explicity asked */
+#undef IPV4_DEFAULT
+
+/* If you have no atexit() but xatexit(), and want to use xatexit() */
+#undef HAVE_XATEXIT
+
+/* getaddrinfo is broken (if present) */
+#undef BROKEN_GETADDRINFO
+
+/* Workaround more Linux IPv6 quirks */
+#undef DONT_TRY_OTHER_AF
+
+/* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */
+#undef IPV4_IN_IPV6
+
+/* Define if you have BSD auth support */
+#undef BSD_AUTH
+
+/* Define if X11 doesn't support AF_UNIX sockets on that system */
+#undef NO_X11_UNIX_SOCKETS
+
+/* Needed for SCO and NeXT */
+#undef BROKEN_SAVED_UIDS
+
+/* Define if your system glob() function has the GLOB_ALTDIRFUNC extension */
+#undef GLOB_HAS_ALTDIRFUNC
+
+/* Define if your system glob() function has gl_matchc options in glob_t */
+#undef GLOB_HAS_GL_MATCHC
+
+/* Define in your struct dirent expects you to allocate extra space for d_name */
+#undef BROKEN_ONE_BYTE_DIRENT_D_NAME
+
+/* Define if your getopt(3) defines and uses optreset */
+#undef HAVE_GETOPT_OPTRESET
+
+/* Define on *nto-qnx systems */
+#undef MISSING_NFDBITS
+
+/* Define on *nto-qnx systems */
+#undef MISSING_HOWMANY
+
+/* Define on *nto-qnx systems */
+#undef MISSING_FD_MASK
+
+/* Define if you want smartcard support */
+#undef SMARTCARD
+
+@BOTTOM@
+
+/* ******************* Shouldn't need to edit below this line ************** */
+
+#include "defines.h"
+
+#endif /* _CONFIG_H */
diff --git a/openssh/aclocal.m4 b/openssh/aclocal.m4
new file mode 100644 (file)
index 0000000..ab9cf4e
--- /dev/null
@@ -0,0 +1,86 @@
+dnl $Id$
+dnl
+dnl OpenSSH-specific autoconf macros
+dnl
+
+
+dnl OSSH_CHECK_HEADER_FOR_FIELD(field, header, symbol)
+dnl Does AC_EGREP_HEADER on 'header' for the string 'field'
+dnl If found, set 'symbol' to be defined. Cache the result.
+dnl TODO: This is not foolproof, better to compile and read from there
+AC_DEFUN(OSSH_CHECK_HEADER_FOR_FIELD, [
+# look for field '$1' in header '$2'
+       dnl This strips characters illegal to m4 from the header filename
+       ossh_safe=`echo "$2" | sed 'y%./+-%__p_%'`
+       dnl
+       ossh_varname="ossh_cv_$ossh_safe""_has_"$1
+       AC_MSG_CHECKING(for $1 field in $2)
+       AC_CACHE_VAL($ossh_varname, [
+               AC_EGREP_HEADER($1, $2, [ dnl
+                       eval "$ossh_varname=yes" dnl
+               ], [ dnl
+                       eval "$ossh_varname=no" dnl
+               ]) dnl
+       ])
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               AC_MSG_RESULT($ossh_result)
+               if test "x$ossh_result" = "xyes"; then
+                       AC_DEFINE($3)
+               fi
+       else
+               AC_MSG_RESULT(no)
+       fi
+])
+
+dnl OSSH_PATH_ENTROPY_PROG(variablename, command):
+dnl Tidiness function, sets 'undef' if not found, and does the AC_SUBST
+AC_DEFUN(OSSH_PATH_ENTROPY_PROG, [
+       AC_PATH_PROG($1, $2)
+       if test -z "[$]$1" ; then
+               $1="undef"
+       fi
+       AC_SUBST($1)
+])
+
+dnl Check for socklen_t: historically on BSD it is an int, and in
+dnl POSIX 1g it is a type of its own, but some platforms use different
+dnl types for the argument to getsockopt, getpeername, etc.  So we
+dnl have to test to find something that will work.
+AC_DEFUN([TYPE_SOCKLEN_T],
+[
+   AC_CHECK_TYPE([socklen_t], ,[
+      AC_MSG_CHECKING([for socklen_t equivalent])
+      AC_CACHE_VAL([curl_cv_socklen_t_equiv],
+      [
+        # Systems have either "struct sockaddr *" or
+        # "void *" as the second argument to getpeername
+        curl_cv_socklen_t_equiv=
+        for arg2 in "struct sockaddr" void; do
+           for t in int size_t unsigned long "unsigned long"; do
+              AC_TRY_COMPILE([
+                 #include <sys/types.h>
+                 #include <sys/socket.h>
+
+                 int getpeername (int, $arg2 *, $t *);
+              ],[
+                 $t len;
+                 getpeername(0,0,&len);
+              ],[
+                 curl_cv_socklen_t_equiv="$t"
+                 break
+              ])
+           done
+        done
+
+        if test "x$curl_cv_socklen_t_equiv" = x; then
+           AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
+        fi
+      ])
+      AC_MSG_RESULT($curl_cv_socklen_t_equiv)
+      AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
+                       [type to use in place of socklen_t if not defined])],
+      [#include <sys/types.h>
+#include <sys/socket.h>])
+])
+
diff --git a/openssh/atomicio.c b/openssh/atomicio.c
new file mode 100644 (file)
index 0000000..47161eb
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp $");
+
+#include "atomicio.h"
+
+/*
+ * ensure all of data on socket comes through. f==read || f==write
+ */
+ssize_t
+atomicio(f, fd, _s, n)
+       ssize_t (*f) ();
+       int fd;
+       void *_s;
+       size_t n;
+{
+       char *s = _s;
+       ssize_t res, pos = 0;
+
+       while (n > pos) {
+               res = (f) (fd, s + pos, n - pos);
+               switch (res) {
+               case -1:
+#ifdef EWOULDBLOCK
+                       if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+#else
+                       if (errno == EINTR || errno == EAGAIN)
+#endif
+                               continue;
+               case 0:
+                       return (res);
+               default:
+                       pos += res;
+               }
+       }
+       return (pos);
+}
diff --git a/openssh/atomicio.h b/openssh/atomicio.h
new file mode 100644 (file)
index 0000000..e569d38
--- /dev/null
@@ -0,0 +1,31 @@
+/*     $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $     */
+
+/*
+ * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Ensure all of data on socket comes through. f==read || f==write
+ */
+ssize_t        atomicio(ssize_t (*)(), int, void *, size_t);
diff --git a/openssh/auth-bsdauth.c b/openssh/auth-bsdauth.c
new file mode 100644 (file)
index 0000000..3732477
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: auth-bsdauth.c,v 1.1 2001/05/18 14:13:28 markus Exp $");
+
+#ifdef BSD_AUTH
+#include "xmalloc.h"
+#include "auth.h"
+#include "log.h"
+
+static void *
+bsdauth_init_ctx(Authctxt *authctxt)
+{
+       return authctxt;
+}
+
+static int
+bsdauth_query(void *ctx, char **name, char **infotxt, 
+   u_int *numprompts, char ***prompts, u_int **echo_on)
+{
+        Authctxt *authctxt = ctx;
+        char *challenge = NULL;
+
+        if (authctxt->as != NULL) {
+                debug2("bsdauth_query: try reuse session");
+                challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
+                if (challenge == NULL) {
+                        auth_close(authctxt->as);
+                        authctxt->as = NULL;
+                }
+        }
+
+        if (challenge == NULL) {
+                debug2("bsdauth_query: new bsd auth session");
+                debug3("bsdauth_query: style %s",
+                   authctxt->style ? authctxt->style : "<default>");
+                authctxt->as = auth_userchallenge(authctxt->user,
+                    authctxt->style, "auth-ssh", &challenge);
+                if (authctxt->as == NULL)
+                        challenge = NULL;
+                debug2("bsdauth_query: <%s>", challenge ? challenge : "empty");
+        }
+        
+        if (challenge == NULL)
+                return -1;
+
+        *name       = xstrdup("");
+        *infotxt    = xstrdup("");
+        *numprompts = 1;
+        *prompts = xmalloc(*numprompts * sizeof(char*));
+        *echo_on = xmalloc(*numprompts * sizeof(u_int));
+        (*echo_on)[0] = 0;
+        (*prompts)[0] = xstrdup(challenge);
+
+        return 0;
+}
+
+static int
+bsdauth_respond(void *ctx, u_int numresponses, char **responses)
+{
+        Authctxt *authctxt = ctx;
+        int authok;
+        
+        if (authctxt->as == 0)
+                error("bsdauth_respond: no bsd auth session");
+
+        if (numresponses != 1)
+                return -1;
+
+        authok = auth_userresponse(authctxt->as, responses[0], 0);
+        authctxt->as = NULL;
+        debug3("bsdauth_respond: <%s> = <%d>", responses[0], authok);
+
+        return (authok == 0) ? -1 : 0;
+}
+
+static void
+bsdauth_free_ctx(void *ctx)
+{
+        Authctxt *authctxt = ctx;
+
+        if (authctxt && authctxt->as) {
+                auth_close(authctxt->as);
+                authctxt->as = NULL;
+        }
+}
+
+KbdintDevice bsdauth_device = {
+       "bsdauth",
+       bsdauth_init_ctx,
+       bsdauth_query,
+       bsdauth_respond,
+       bsdauth_free_ctx
+};
+#endif
diff --git a/openssh/auth-chall.c b/openssh/auth-chall.c
new file mode 100644 (file)
index 0000000..45e0c34
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-chall.c,v 1.8 2001/05/18 14:13:28 markus Exp $");
+
+#include "auth.h"
+#include "log.h"
+#include "xmalloc.h"
+
+/* limited protocol v1 interface to kbd-interactive authentication */
+
+extern KbdintDevice *devices[];
+static KbdintDevice *device;
+
+char *
+get_challenge(Authctxt *authctxt)
+{
+       char *challenge, *name, *info, **prompts;
+       u_int i, numprompts;
+       u_int *echo_on;
+
+       device = devices[0]; /* we always use the 1st device for protocol 1 */
+       if (device == NULL)
+               return NULL;
+       if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
+               return NULL;
+       if (device->query(authctxt->kbdintctxt, &name, &info,
+           &numprompts, &prompts, &echo_on)) {
+               device->free_ctx(authctxt->kbdintctxt);
+               authctxt->kbdintctxt = NULL;
+               return NULL;
+       }
+       if (numprompts < 1)
+               fatal("get_challenge: numprompts < 1");
+       challenge = xstrdup(prompts[0]);
+       for (i = 0; i < numprompts; i++)
+               xfree(prompts[i]);
+       xfree(prompts);
+       xfree(name);
+       xfree(echo_on);
+       xfree(info);
+
+       return (challenge);
+}
+int
+verify_response(Authctxt *authctxt, const char *response)
+{
+       char *resp[1];
+       int res;
+
+       if (device == NULL)
+               return 0;
+       if (authctxt->kbdintctxt == NULL)
+               return 0;
+       resp[0] = (char *)response;
+       res = device->respond(authctxt->kbdintctxt, 1, resp);
+       device->free_ctx(authctxt->kbdintctxt);
+       authctxt->kbdintctxt = NULL;
+       return res ? 0 : 1;
+}
diff --git a/openssh/auth-krb4.c b/openssh/auth-krb4.c
new file mode 100644 (file)
index 0000000..031dcd3
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 1999 Dug Song.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-krb4.c,v 1.24 2001/06/26 16:15:22 dugsong Exp $");
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "auth.h"
+
+#ifdef AFS
+#include "radix.h"
+#endif
+
+#ifdef KRB4
+extern ServerOptions options;
+
+static int
+krb4_init(void *context)
+{
+       static int cleanup_registered = 0;
+       Authctxt *authctxt = (Authctxt *)context;
+       const char *tkt_root = TKT_ROOT;
+       struct stat st;
+       int fd;
+       
+       if (!authctxt->krb4_ticket_file) {
+               /* Set unique ticket string manually since we're still root. */
+               authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN);
+#ifdef AFS
+               if (lstat("/ticket", &st) != -1)
+                       tkt_root = "/ticket/";
+#endif /* AFS */
+               snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%d",
+                   tkt_root, authctxt->pw->pw_uid, getpid());
+               krb_set_tkt_string(authctxt->krb4_ticket_file);
+       }
+       /* Register ticket cleanup in case of fatal error. */
+       if (!cleanup_registered) {
+               fatal_add_cleanup(krb4_cleanup_proc, authctxt);
+               cleanup_registered = 1;
+       }
+       /* Try to create our ticket file. */
+       if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) {
+               close(fd);
+               return (1);
+       }
+       /* Ticket file exists - make sure user owns it (just passed ticket). */
+       if (lstat(authctxt->krb4_ticket_file, &st) != -1) {
+               if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
+                   st.st_uid == authctxt->pw->pw_uid)
+                       return (1);
+       }
+       /* Failure - cancel cleanup function, leaving ticket for inspection. */
+       log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file);
+       
+       fatal_remove_cleanup(krb4_cleanup_proc, authctxt);
+       cleanup_registered = 0;
+       
+       xfree(authctxt->krb4_ticket_file);
+       authctxt->krb4_ticket_file = NULL;
+       
+       return (0);
+}
+
+/*
+ * try krb4 authentication,
+ * return 1 on success, 0 on failure, -1 if krb4 is not available
+ */
+int
+auth_krb4_password(Authctxt *authctxt, const char *password)
+{
+       AUTH_DAT adata;
+       KTEXT_ST tkt;
+       struct hostent *hp;
+       struct passwd *pw;
+       char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
+       u_int32_t faddr;
+       int r;
+       
+       if ((pw = authctxt->pw) == NULL)
+               return (0);
+       
+       /*
+        * Try Kerberos password authentication only for non-root
+        * users and only if Kerberos is installed.
+        */
+       if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
+               /* Set up our ticket file. */
+               if (!krb4_init(authctxt)) {
+                       log("Couldn't initialize Kerberos ticket file for %s!",
+                           pw->pw_name);
+                       goto failure;
+               }
+               /* Try to get TGT using our password. */
+               r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
+                   "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
+               if (r != INTK_OK) {
+                       debug("Kerberos v4 password authentication for %s "
+                           "failed: %s", pw->pw_name, krb_err_txt[r]);
+                       goto failure;
+               }
+               /* Successful authentication. */
+               chown(tkt_string(), pw->pw_uid, pw->pw_gid);
+               
+               /*
+                * Now that we have a TGT, try to get a local
+                * "rcmd" ticket to ensure that we are not talking
+                * to a bogus Kerberos server.
+                */
+               gethostname(localhost, sizeof(localhost));
+               strlcpy(phost, (char *)krb_get_phost(localhost),
+                   sizeof(phost));
+               r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
+               
+               if (r == KSUCCESS) {
+                       if ((hp = gethostbyname(localhost)) == NULL) {
+                               log("Couldn't get local host address!");
+                               goto failure;
+                       }
+                       memmove((void *)&faddr, (void *)hp->h_addr,
+                           sizeof(faddr));
+                       
+                       /* Verify our "rcmd" ticket. */
+                       r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
+                           faddr, &adata, "");
+                       if (r == RD_AP_UNDEC) {
+                               /*
+                                * Probably didn't have a srvtab on
+                                * localhost. Disallow login.
+                                */
+                               log("Kerberos v4 TGT for %s unverifiable, "
+                                   "no srvtab installed? krb_rd_req: %s",
+                                   pw->pw_name, krb_err_txt[r]);
+                               goto failure;
+                       } else if (r != KSUCCESS) {
+                               log("Kerberos v4 %s ticket unverifiable: %s",
+                                   KRB4_SERVICE_NAME, krb_err_txt[r]);
+                               goto failure;
+                       }
+               } else if (r == KDC_PR_UNKNOWN) {
+                       /*
+                        * Disallow login if no rcmd service exists, and
+                        * log the error.
+                        */
+                       log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
+                           "not registered, or srvtab is wrong?", pw->pw_name,
+                           krb_err_txt[r], KRB4_SERVICE_NAME, phost);
+                       goto failure;
+               } else {
+                       /*
+                        * TGT is bad, forget it. Possibly spoofed!
+                        */
+                       debug("WARNING: Kerberos v4 TGT possibly spoofed "
+                           "for %s: %s", pw->pw_name, krb_err_txt[r]);
+                       goto failure;
+               }
+               /* Authentication succeeded. */
+               return (1);
+       } else
+               /* Logging in as root or no local Kerberos realm. */
+               debug("Unable to authenticate to Kerberos.");
+       
+ failure:
+       krb4_cleanup_proc(authctxt);
+       
+       if (!options.kerberos_or_local_passwd)
+               return (0);
+       
+       /* Fall back to ordinary passwd authentication. */
+       return (-1);
+}
+
+void
+krb4_cleanup_proc(void *context)
+{
+       Authctxt *authctxt = (Authctxt *)context;
+       debug("krb4_cleanup_proc called");
+       if (authctxt->krb4_ticket_file) {
+               (void) dest_tkt();
+               xfree(authctxt->krb4_ticket_file);
+               authctxt->krb4_ticket_file = NULL;
+       }
+}
+
+int
+auth_krb4(Authctxt *authctxt, KTEXT auth, char **client)
+{
+       AUTH_DAT adat = {0};
+       KTEXT_ST reply;
+       Key_schedule schedule;
+       struct sockaddr_in local, foreign;
+       char instance[INST_SZ];
+       socklen_t slen;
+       u_int cksum;
+       int r, s;
+       
+       s = packet_get_connection_in();
+       
+       slen = sizeof(local);
+       memset(&local, 0, sizeof(local));
+       if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
+               debug("getsockname failed: %.100s", strerror(errno));
+       slen = sizeof(foreign);
+       memset(&foreign, 0, sizeof(foreign));
+       if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) {
+               debug("getpeername failed: %.100s", strerror(errno));
+               fatal_cleanup();
+       }
+       instance[0] = '*';
+       instance[1] = 0;
+       
+       /* Get the encrypted request, challenge, and session key. */
+       if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
+           0, &adat, ""))) {
+               debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
+               return (0);
+       }
+       des_key_sched((des_cblock *) adat.session, schedule);
+       
+       *client = xmalloc(MAX_K_NAME_SZ);
+       (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
+           *adat.pinst ? "." : "", adat.pinst, adat.prealm);
+       
+       /* Check ~/.klogin authorization now. */
+       if (kuserok(&adat, authctxt->user) != KSUCCESS) {
+               log("Kerberos v4 .klogin authorization failed for %s to "
+                   "account %s", *client, authctxt->user);
+               xfree(*client);
+               return (0);
+       }
+       /* Increment the checksum, and return it encrypted with the
+          session key. */
+       cksum = adat.checksum + 1;
+       cksum = htonl(cksum);
+       
+       /* If we can't successfully encrypt the checksum, we send back an
+          empty message, admitting our failure. */
+       if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
+           schedule, &adat.session, &local, &foreign)) < 0) {
+               debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
+               reply.dat[0] = 0;
+               reply.length = 0;
+       } else
+               reply.length = r;
+       
+       /* Clear session key. */
+       memset(&adat.session, 0, sizeof(&adat.session));
+       
+       packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
+       packet_put_string((char *) reply.dat, reply.length);
+       packet_send();
+       packet_write_wait();
+       return (1);
+}
+#endif /* KRB4 */
+
+#ifdef AFS
+int
+auth_krb4_tgt(Authctxt *authctxt, const char *string)
+{
+       CREDENTIALS creds;
+       struct passwd *pw;
+       
+       if ((pw = authctxt->pw) == NULL)
+               goto failure;
+       
+       temporarily_use_uid(pw);
+       
+       if (!radix_to_creds(string, &creds)) {
+               log("Protocol error decoding Kerberos v4 TGT");
+               goto failure;
+       }
+       if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
+               strlcpy(creds.service, "krbtgt", sizeof creds.service);
+       
+       if (strcmp(creds.service, "krbtgt")) {
+               log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
+                   creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
+                   creds.realm, pw->pw_name);
+               goto failure;
+       }
+       if (!krb4_init(authctxt))
+               goto failure;
+       
+       if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
+               goto failure;
+       
+       if (save_credentials(creds.service, creds.instance, creds.realm,
+           creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
+           creds.issue_date) != KSUCCESS) {
+               debug("Kerberos v4 TGT refused: couldn't save credentials");
+               goto failure;
+       }
+       /* Successful authentication, passed all checks. */
+       chown(tkt_string(), pw->pw_uid, pw->pw_gid);
+       
+       debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
+           creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
+       memset(&creds, 0, sizeof(creds));
+       
+       restore_uid();
+       
+       return (1);
+       
+ failure:
+       krb4_cleanup_proc(authctxt);
+       memset(&creds, 0, sizeof(creds));
+       restore_uid();
+       
+       return (0);
+}
+
+int
+auth_afs_token(Authctxt *authctxt, const char *token_string)
+{
+       CREDENTIALS creds;
+       struct passwd *pw;
+       uid_t uid;
+       
+       if ((pw = authctxt->pw) == NULL)
+               return (0);
+       
+       if (!radix_to_creds(token_string, &creds)) {
+               log("Protocol error decoding AFS token");
+               return (0);
+       }
+       if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
+               strlcpy(creds.service, "afs", sizeof creds.service);
+       
+       if (strncmp(creds.pname, "AFS ID ", 7) == 0)
+               uid = atoi(creds.pname + 7);
+       else
+               uid = pw->pw_uid;
+       
+       if (kafs_settoken(creds.realm, uid, &creds)) {
+               log("AFS token (%s@%s) rejected for %s",
+                   creds.pname, creds.realm, pw->pw_name);
+               memset(&creds, 0, sizeof(creds));
+               return (0);
+       }
+       debug("AFS token accepted (%s@%s)", creds.pname, creds.realm);
+       memset(&creds, 0, sizeof(creds));
+       
+       return (1);
+}
+#endif /* AFS */
diff --git a/openssh/auth-krb5.c b/openssh/auth-krb5.c
new file mode 100644 (file)
index 0000000..b56f43a
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ *    Kerberos v5 authentication and ticket-passing routines.
+ * 
+ * $FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp $
+ * $OpenBSD: auth-krb5.c,v 1.2 2001/11/12 01:47:09 dugsong Exp $
+ */
+
+#include "includes.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "auth.h"
+
+#ifdef KRB5
+#include <krb5.h>
+
+extern ServerOptions    options;
+
+static int
+krb5_init(void *context)
+{
+       Authctxt *authctxt = (Authctxt *)context;
+       krb5_error_code problem;
+       static int cleanup_registered = 0;
+       
+       if (authctxt->krb5_ctx == NULL) {
+               problem = krb5_init_context(&authctxt->krb5_ctx);
+               if (problem)
+                       return (problem);
+               krb5_init_ets(authctxt->krb5_ctx);
+       }
+       if (!cleanup_registered) {
+               fatal_add_cleanup(krb5_cleanup_proc, authctxt);
+               cleanup_registered = 1;
+       }
+       return (0);
+}
+
+/*
+ * Try krb5 authentication. server_user is passed for logging purposes
+ * only, in auth is received ticket, in client is returned principal
+ * from the ticket
+ */
+int 
+auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client)
+{
+       krb5_error_code problem;
+       krb5_principal server;
+       krb5_data reply;
+       krb5_ticket *ticket;
+       int fd, ret;
+
+       ret = 0;
+       server = NULL;
+       ticket = NULL;
+       reply.length = 0;
+       
+       problem = krb5_init(authctxt);
+       if (problem) 
+               goto err;
+       
+       problem = krb5_auth_con_init(authctxt->krb5_ctx,
+           &authctxt->krb5_auth_ctx);
+       if (problem)
+               goto err;
+       
+       fd = packet_get_connection_in();
+       problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx,
+           authctxt->krb5_auth_ctx, &fd);
+       if (problem)
+               goto err;
+       
+       problem = krb5_sname_to_principal(authctxt->krb5_ctx,  NULL, NULL ,
+           KRB5_NT_SRV_HST, &server);
+       if (problem)
+               goto err;
+       
+       problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx,
+           auth, server, NULL, NULL, &ticket);
+       if (problem)
+               goto err;
+       
+       problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client,
+           &authctxt->krb5_user);
+       if (problem)
+               goto err;
+       
+       /* if client wants mutual auth */
+       problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
+           &reply);
+       if (problem)
+               goto err;
+       
+       /* Check .k5login authorization now. */
+       if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
+           authctxt->pw->pw_name))
+               goto err;
+       
+       if (client)
+               krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
+                   client);
+       
+       packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
+       packet_put_string((char *) reply.data, reply.length);
+       packet_send();
+       packet_write_wait();
+
+       ret = 1;
+ err:
+       if (server)
+               krb5_free_principal(authctxt->krb5_ctx, server);
+       if (ticket)
+               krb5_free_ticket(authctxt->krb5_ctx, ticket);
+       if (reply.length)
+               xfree(reply.data);
+       
+       if (problem)
+               debug("Kerberos v5 authentication failed: %s",
+                   krb5_get_err_text(authctxt->krb5_ctx, problem));
+
+       return (ret);
+}
+
+int
+auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt)
+{
+       krb5_error_code problem;
+       krb5_ccache ccache = NULL;
+       char *pname;
+       
+       if (authctxt->pw == NULL || authctxt->krb5_user == NULL)
+               return (0);
+       
+       temporarily_use_uid(authctxt->pw);
+       
+       problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
+       if (problem)
+               goto fail;
+       
+       problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
+           authctxt->krb5_user);
+       if (problem)
+               goto fail;
+       
+       problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
+           ccache, tgt);
+       if (problem)
+               goto fail;
+       
+       authctxt->krb5_fwd_ccache = ccache;
+       ccache = NULL;
+       
+       authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+       
+       problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
+           &pname);
+       if (problem)
+               goto fail;
+       
+       debug("Kerberos v5 TGT accepted (%s)", pname);
+       
+       restore_uid();
+       
+       return (1);
+       
+ fail:
+       if (problem)
+               debug("Kerberos v5 TGT passing failed: %s",
+                   krb5_get_err_text(authctxt->krb5_ctx, problem));
+       if (ccache)
+               krb5_cc_destroy(authctxt->krb5_ctx, ccache);
+       
+       restore_uid();
+       
+       return (0);
+}
+
+int
+auth_krb5_password(Authctxt *authctxt, const char *password)
+{
+       krb5_error_code problem;
+       
+       if (authctxt->pw == NULL)
+               return (0);
+       
+       temporarily_use_uid(authctxt->pw);
+       
+       problem = krb5_init(authctxt);
+       if (problem)
+               goto out;
+       
+       problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
+                   &authctxt->krb5_user);
+       if (problem)
+               goto out;
+       
+       problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
+           &authctxt->krb5_fwd_ccache);
+       if (problem)
+               goto out;
+       
+       problem = krb5_cc_initialize(authctxt->krb5_ctx,
+           authctxt->krb5_fwd_ccache, authctxt->krb5_user);
+       if (problem)
+               goto out;
+       
+       problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
+           authctxt->krb5_fwd_ccache, password, 1, NULL);
+       if (problem)
+               goto out;
+       
+       authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+       
+ out:
+       restore_uid();
+       
+       if (problem) {
+               debug("Kerberos password authentication failed: %s",
+                   krb5_get_err_text(authctxt->krb5_ctx, problem));
+               
+               krb5_cleanup_proc(authctxt);
+               
+               if (options.kerberos_or_local_passwd)
+                       return (-1);
+               else
+                       return (0);
+       }
+       return (1);
+}
+
+void
+krb5_cleanup_proc(void *context)
+{
+       Authctxt *authctxt = (Authctxt *)context;
+       
+       debug("krb5_cleanup_proc called");
+       if (authctxt->krb5_fwd_ccache) {
+               krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+               authctxt->krb5_fwd_ccache = NULL;
+       }
+       if (authctxt->krb5_user) {
+               krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
+               authctxt->krb5_user = NULL;
+       }
+       if (authctxt->krb5_auth_ctx) {
+               krb5_auth_con_free(authctxt->krb5_ctx,
+                   authctxt->krb5_auth_ctx);
+               authctxt->krb5_auth_ctx = NULL;
+       }
+       if (authctxt->krb5_ctx) {
+               krb5_free_context(authctxt->krb5_ctx);
+               authctxt->krb5_ctx = NULL;
+       }
+}
+
+#endif /* KRB5 */
diff --git a/openssh/auth-options.c b/openssh/auth-options.c
new file mode 100644 (file)
index 0000000..9f90437
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-options.c,v 1.20 2001/08/30 20:36:34 stevesk Exp $");
+
+#include "packet.h"
+#include "xmalloc.h"
+#include "match.h"
+#include "log.h"
+#include "canohost.h"
+#include "channels.h"
+#include "auth-options.h"
+#include "servconf.h"
+#include "misc.h"
+
+/* Flags set authorized_keys flags */
+int no_port_forwarding_flag = 0;
+int no_agent_forwarding_flag = 0;
+int no_x11_forwarding_flag = 0;
+int no_pty_flag = 0;
+
+/* "command=" option. */
+char *forced_command = NULL;
+
+/* "environment=" options. */
+struct envstring *custom_environment = NULL;
+
+extern ServerOptions options;
+
+void
+auth_clear_options(void)
+{
+       no_agent_forwarding_flag = 0;
+       no_port_forwarding_flag = 0;
+       no_pty_flag = 0;
+       no_x11_forwarding_flag = 0;
+       while (custom_environment) {
+               struct envstring *ce = custom_environment;
+               custom_environment = ce->next;
+               xfree(ce->s);
+               xfree(ce);
+       }
+       if (forced_command) {
+               xfree(forced_command);
+               forced_command = NULL;
+       }
+       channel_clear_permitted_opens();
+}
+
+/*
+ * return 1 if access is granted, 0 if not.
+ * side effect: sets key option flags
+ */
+int
+auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
+{
+       const char *cp;
+       int i;
+
+       /* reset options */
+       auth_clear_options();
+
+       if (!opts)
+               return 1;
+
+       while (*opts && *opts != ' ' && *opts != '\t') {
+               cp = "no-port-forwarding";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       packet_send_debug("Port forwarding disabled.");
+                       no_port_forwarding_flag = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "no-agent-forwarding";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       packet_send_debug("Agent forwarding disabled.");
+                       no_agent_forwarding_flag = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "no-X11-forwarding";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       packet_send_debug("X11 forwarding disabled.");
+                       no_x11_forwarding_flag = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "no-pty";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       packet_send_debug("Pty allocation disabled.");
+                       no_pty_flag = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "command=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       opts += strlen(cp);
+                       forced_command = xmalloc(strlen(opts) + 1);
+                       i = 0;
+                       while (*opts) {
+                               if (*opts == '"')
+                                       break;
+                               if (*opts == '\\' && opts[1] == '"') {
+                                       opts += 2;
+                                       forced_command[i++] = '"';
+                                       continue;
+                               }
+                               forced_command[i++] = *opts++;
+                       }
+                       if (!*opts) {
+                               debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               packet_send_debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(forced_command);
+                               forced_command = NULL;
+                               goto bad_option;
+                       }
+                       forced_command[i] = 0;
+                       packet_send_debug("Forced command: %.900s", forced_command);
+                       opts++;
+                       goto next_option;
+               }
+               cp = "environment=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       char *s;
+                       struct envstring *new_envstring;
+
+                       opts += strlen(cp);
+                       s = xmalloc(strlen(opts) + 1);
+                       i = 0;
+                       while (*opts) {
+                               if (*opts == '"')
+                                       break;
+                               if (*opts == '\\' && opts[1] == '"') {
+                                       opts += 2;
+                                       s[i++] = '"';
+                                       continue;
+                               }
+                               s[i++] = *opts++;
+                       }
+                       if (!*opts) {
+                               debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               packet_send_debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(s);
+                               goto bad_option;
+                       }
+                       s[i] = 0;
+                       packet_send_debug("Adding to environment: %.900s", s);
+                       debug("Adding to environment: %.900s", s);
+                       opts++;
+                       new_envstring = xmalloc(sizeof(struct envstring));
+                       new_envstring->s = s;
+                       new_envstring->next = custom_environment;
+                       custom_environment = new_envstring;
+                       goto next_option;
+               }
+               cp = "from=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       const char *remote_ip = get_remote_ipaddr();
+                       const char *remote_host = get_canonical_hostname(
+                           options.reverse_mapping_check);
+                       char *patterns = xmalloc(strlen(opts) + 1);
+
+                       opts += strlen(cp);
+                       i = 0;
+                       while (*opts) {
+                               if (*opts == '"')
+                                       break;
+                               if (*opts == '\\' && opts[1] == '"') {
+                                       opts += 2;
+                                       patterns[i++] = '"';
+                                       continue;
+                               }
+                               patterns[i++] = *opts++;
+                       }
+                       if (!*opts) {
+                               debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               packet_send_debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       patterns[i] = 0;
+                       opts++;
+                       if (match_host_and_ip(remote_host, remote_ip,
+                           patterns) != 1) {
+                               xfree(patterns);
+                               log("Authentication tried for %.100s with "
+                                   "correct key but not from a permitted "
+                                   "host (host=%.200s, ip=%.200s).",
+                                   pw->pw_name, remote_host, remote_ip);
+                               packet_send_debug("Your host '%.200s' is not "
+                                   "permitted to use this key for login.",
+                                   remote_host);
+                               /* deny access */
+                               return 0;
+                       }
+                       xfree(patterns);
+                       /* Host name matches. */
+                       goto next_option;
+               }
+               cp = "permitopen=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       char host[256], sport[6];
+                       u_short port;
+                       char *patterns = xmalloc(strlen(opts) + 1);
+
+                       opts += strlen(cp);
+                       i = 0;
+                       while (*opts) {
+                               if (*opts == '"')
+                                       break;
+                               if (*opts == '\\' && opts[1] == '"') {
+                                       opts += 2;
+                                       patterns[i++] = '"';
+                                       continue;
+                               }
+                               patterns[i++] = *opts++;
+                       }
+                       if (!*opts) {
+                               debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               packet_send_debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       patterns[i] = 0;
+                       opts++;
+                       if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
+                           sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
+                               debug("%.100s, line %lu: Bad permitopen specification "
+                                   "<%.100s>", file, linenum, patterns);
+                               packet_send_debug("%.100s, line %lu: "
+                                   "Bad permitopen specification", file, linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       if ((port = a2port(sport)) == 0) {
+                               debug("%.100s, line %lu: Bad permitopen port <%.100s>",
+                                   file, linenum, sport);
+                               packet_send_debug("%.100s, line %lu: "
+                                   "Bad permitopen port", file, linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       if (options.allow_tcp_forwarding)
+                               channel_add_permitted_opens(host, port);
+                       xfree(patterns);
+                       goto next_option;
+               }
+next_option:
+               /*
+                * Skip the comma, and move to the next option
+                * (or break out if there are no more).
+                */
+               if (!*opts)
+                       fatal("Bugs in auth-options.c option processing.");
+               if (*opts == ' ' || *opts == '\t')
+                       break;          /* End of options. */
+               if (*opts != ',')
+                       goto bad_option;
+               opts++;
+               /* Process the next option. */
+       }
+       /* grant access */
+       return 1;
+
+bad_option:
+       log("Bad options in %.100s file, line %lu: %.50s",
+           file, linenum, opts);
+       packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
+           file, linenum, opts);
+       /* deny access */
+       return 0;
+}
diff --git a/openssh/auth-options.h b/openssh/auth-options.h
new file mode 100644 (file)
index 0000000..3b2ce34
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions to interface with the SSH_AUTHENTICATION_FD socket.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* $OpenBSD: auth-options.h,v 1.10 2001/06/26 17:27:22 markus Exp $ */
+
+#ifndef AUTH_OPTIONS_H
+#define AUTH_OPTIONS_H
+
+/* Linked list of custom environment strings */
+struct envstring {
+       struct envstring *next;
+       char   *s;
+};
+
+/* Flags that may be set in authorized_keys options. */
+extern int no_port_forwarding_flag;
+extern int no_agent_forwarding_flag;
+extern int no_x11_forwarding_flag;
+extern int no_pty_flag;
+extern char *forced_command;
+extern struct envstring *custom_environment;
+
+int    auth_parse_options(struct passwd *, char *, char *, u_long);
+void   auth_clear_options(void);
+
+#endif
diff --git a/openssh/auth-pam.c b/openssh/auth-pam.c
new file mode 100644 (file)
index 0000000..801c9eb
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifdef USE_PAM
+#include "ssh.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "auth-pam.h"
+#include "servconf.h"
+#include "canohost.h"
+#include "readpass.h"
+
+extern char *__progname;
+
+RCSID("$Id$");
+
+#define NEW_AUTHTOK_MSG \
+       "Warning: Your password has expired, please change it now"
+
+static int do_pam_conversation(int num_msg, const struct pam_message **msg,
+       struct pam_response **resp, void *appdata_ptr);
+
+/* module-local variables */
+static struct pam_conv conv = {
+       do_pam_conversation,
+       NULL
+};
+static char *__pam_msg = NULL;
+static pam_handle_t *__pamh = NULL;
+static const char *__pampasswd = NULL;
+
+/* states for do_pam_conversation() */
+enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
+/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */
+static int password_change_required = 0;
+/* remember whether the last pam_authenticate() succeeded or not */
+static int was_authenticated = 0;
+
+/* Remember what has been initialised */
+static int session_opened = 0;
+static int creds_set = 0;
+
+/* accessor which allows us to switch conversation structs according to
+ * the authentication method being used */
+void do_pam_set_conv(struct pam_conv *conv)
+{
+       pam_set_item(__pamh, PAM_CONV, conv);
+}
+
+/* start an authentication run */
+int do_pam_authenticate(int flags)
+{
+       int retval = pam_authenticate(__pamh, flags);
+       was_authenticated = (retval == PAM_SUCCESS);
+       return retval;
+}
+
+/*
+ * PAM conversation function.
+ * There are two states this can run in.
+ *
+ * INITIAL_LOGIN mode simply feeds the password from the client into
+ * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output
+ * messages with into __pam_msg.  This is used during initial
+ * authentication to bypass the normal PAM password prompt.
+ *
+ * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase()
+ * and outputs messages to stderr. This mode is used if pam_chauthtok()
+ * is called to update expired passwords.
+ */
+static int do_pam_conversation(int num_msg, const struct pam_message **msg,
+       struct pam_response **resp, void *appdata_ptr)
+{
+       struct pam_response *reply;
+       int count;
+       char buf[1024];
+
+       /* PAM will free this later */
+       reply = malloc(num_msg * sizeof(*reply));
+       if (reply == NULL)
+               return PAM_CONV_ERR;
+
+       for (count = 0; count < num_msg; count++) {
+               if (pamstate == INITIAL_LOGIN) {
+                       /*
+                        * We can't use stdio yet, queue messages for 
+                        * printing later
+                        */
+                       switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
+                       case PAM_PROMPT_ECHO_ON:
+                               free(reply);
+                               return PAM_CONV_ERR;
+                       case PAM_PROMPT_ECHO_OFF:
+                               if (__pampasswd == NULL) {
+                                       free(reply);
+                                       return PAM_CONV_ERR;
+                               }
+                               reply[count].resp = xstrdup(__pampasswd);
+                               reply[count].resp_retcode = PAM_SUCCESS;
+                               break;
+                       case PAM_ERROR_MSG:
+                       case PAM_TEXT_INFO:
+                               if ((*msg)[count].msg != NULL) {
+                                       message_cat(&__pam_msg, 
+                                           PAM_MSG_MEMBER(msg, count, msg));
+                               }
+                               reply[count].resp = xstrdup("");
+                               reply[count].resp_retcode = PAM_SUCCESS;
+                               break;
+                       default:
+                               free(reply);
+                               return PAM_CONV_ERR;
+                       }
+               } else {
+                       /*
+                        * stdio is connected, so interact directly
+                        */
+                       switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
+                       case PAM_PROMPT_ECHO_ON:
+                               fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
+                               fgets(buf, sizeof(buf), stdin);
+                               reply[count].resp = xstrdup(buf);
+                               reply[count].resp_retcode = PAM_SUCCESS;
+                               break;
+                       case PAM_PROMPT_ECHO_OFF:
+                               reply[count].resp = 
+                                   read_passphrase(PAM_MSG_MEMBER(msg, count,
+                                       msg), RP_ALLOW_STDIN);
+                               reply[count].resp_retcode = PAM_SUCCESS;
+                               break;
+                       case PAM_ERROR_MSG:
+                       case PAM_TEXT_INFO:
+                               if ((*msg)[count].msg != NULL)
+                                       fprintf(stderr, "%s\n", 
+                                           PAM_MSG_MEMBER(msg, count, msg));
+                               reply[count].resp = xstrdup("");
+                               reply[count].resp_retcode = PAM_SUCCESS;
+                               break;
+                       default:
+                               free(reply);
+                               return PAM_CONV_ERR;
+                       }
+               }
+       }
+
+       *resp = reply;
+
+       return PAM_SUCCESS;
+}
+
+/* Called at exit to cleanly shutdown PAM */
+void do_pam_cleanup_proc(void *context)
+{
+       int pam_retval = PAM_SUCCESS;
+
+       if (__pamh && session_opened) {
+               pam_retval = pam_close_session(__pamh, 0);
+               if (pam_retval != PAM_SUCCESS)
+                       log("Cannot close PAM session[%d]: %.200s",
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+       }
+
+       if (__pamh && creds_set) {
+               pam_retval = pam_setcred(__pamh, PAM_DELETE_CRED);
+               if (pam_retval != PAM_SUCCESS)
+                       debug("Cannot delete credentials[%d]: %.200s", 
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+       }
+
+       if (__pamh) {
+               pam_retval = pam_end(__pamh, pam_retval);
+               if (pam_retval != PAM_SUCCESS)
+                       log("Cannot release PAM authentication[%d]: %.200s",
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+       }
+}
+
+/* Attempt password authentation using PAM */
+int auth_pam_password(struct passwd *pw, const char *password)
+{
+       extern ServerOptions options;
+       int pam_retval;
+
+       do_pam_set_conv(&conv);
+
+       /* deny if no user. */
+       if (pw == NULL)
+               return 0;
+       if (pw->pw_uid == 0 && options.permit_root_login == PERMIT_NO_PASSWD)
+               return 0;
+       if (*password == '\0' && options.permit_empty_passwd == 0)
+               return 0;
+
+       __pampasswd = password;
+
+       pamstate = INITIAL_LOGIN;
+       pam_retval = do_pam_authenticate(
+           options.permit_empty_passwd == 0 ? PAM_DISALLOW_NULL_AUTHTOK : 0);
+       if (pam_retval == PAM_SUCCESS) {
+               debug("PAM Password authentication accepted for "
+                   "user \"%.100s\"", pw->pw_name);
+               return 1;
+       } else {
+               debug("PAM Password authentication for \"%.100s\" "
+                   "failed[%d]: %s", pw->pw_name, pam_retval, 
+                   PAM_STRERROR(__pamh, pam_retval));
+               return 0;
+       }
+}
+
+/* Do account management using PAM */
+int do_pam_account(char *username, char *remote_user)
+{
+       int pam_retval;
+
+       do_pam_set_conv(&conv);
+
+       if (remote_user) {
+               debug("PAM setting ruser to \"%.200s\"", remote_user);
+               pam_retval = pam_set_item(__pamh, PAM_RUSER, remote_user);
+               if (pam_retval != PAM_SUCCESS)
+                       fatal("PAM set ruser failed[%d]: %.200s", pam_retval, 
+                           PAM_STRERROR(__pamh, pam_retval));
+       }
+
+       pam_retval = pam_acct_mgmt(__pamh, 0);
+       switch (pam_retval) {
+               case PAM_SUCCESS:
+                       /* This is what we want */
+                       break;
+               case PAM_NEW_AUTHTOK_REQD:
+                       message_cat(&__pam_msg, NEW_AUTHTOK_MSG);
+                       /* flag that password change is necessary */
+                       password_change_required = 1;
+                       break;
+               default:
+                       log("PAM rejected by account configuration[%d]: "
+                           "%.200s", pam_retval, PAM_STRERROR(__pamh, 
+                           pam_retval));
+                       return(0);
+       }
+
+       return(1);
+}
+
+/* Do PAM-specific session initialisation */
+void do_pam_session(char *username, const char *ttyname)
+{
+       int pam_retval;
+
+       do_pam_set_conv(&conv);
+
+       if (ttyname != NULL) {
+               debug("PAM setting tty to \"%.200s\"", ttyname);
+               pam_retval = pam_set_item(__pamh, PAM_TTY, ttyname);
+               if (pam_retval != PAM_SUCCESS)
+                       fatal("PAM set tty failed[%d]: %.200s",
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+       }
+
+       pam_retval = pam_open_session(__pamh, 0);
+       if (pam_retval != PAM_SUCCESS)
+               fatal("PAM session setup failed[%d]: %.200s",
+                   pam_retval, PAM_STRERROR(__pamh, pam_retval));
+
+       session_opened = 1;
+}
+
+/* Set PAM credentials */
+void do_pam_setcred(int init)
+{
+       int pam_retval;
+
+       do_pam_set_conv(&conv);
+
+       debug("PAM establishing creds");
+       pam_retval = pam_setcred(__pamh, 
+           init ? PAM_ESTABLISH_CRED : PAM_REINITIALIZE_CRED);
+       if (pam_retval != PAM_SUCCESS) {
+               if (was_authenticated)
+                       fatal("PAM setcred failed[%d]: %.200s",
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+               else
+                       debug("PAM setcred failed[%d]: %.200s",
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+       } else
+               creds_set = 1;
+}
+
+/* accessor function for file scope static variable */
+int is_pam_password_change_required(void)
+{
+       return password_change_required;
+}
+
+/*
+ * Have user change authentication token if pam_acct_mgmt() indicated
+ * it was expired.  This needs to be called after an interactive
+ * session is established and the user's pty is connected to
+ * stdin/stout/stderr.
+ */
+void do_pam_chauthtok(void)
+{
+       int pam_retval;
+
+       do_pam_set_conv(&conv);
+
+       if (password_change_required) {
+               pamstate = OTHER;
+               pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+               if (pam_retval != PAM_SUCCESS)
+                       fatal("PAM pam_chauthtok failed[%d]: %.200s",
+                           pam_retval, PAM_STRERROR(__pamh, pam_retval));
+       }
+}
+
+/* Cleanly shutdown PAM */
+void finish_pam(void)
+{
+       do_pam_cleanup_proc(NULL);
+       fatal_remove_cleanup(&do_pam_cleanup_proc, NULL);
+}
+
+/* Start PAM authentication for specified account */
+void start_pam(const char *user)
+{
+       int pam_retval;
+       extern ServerOptions options;
+       extern u_int utmp_len;
+       const char *rhost;
+
+       debug("Starting up PAM with username \"%.200s\"", user);
+
+       pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &__pamh);
+
+       if (pam_retval != PAM_SUCCESS)
+               fatal("PAM initialisation failed[%d]: %.200s",
+                   pam_retval, PAM_STRERROR(__pamh, pam_retval));
+
+       rhost = get_remote_name_or_ip(utmp_len, options.reverse_mapping_check);
+       debug("PAM setting rhost to \"%.200s\"", rhost);
+
+       pam_retval = pam_set_item(__pamh, PAM_RHOST, rhost);
+       if (pam_retval != PAM_SUCCESS)
+               fatal("PAM set rhost failed[%d]: %.200s", pam_retval,
+                   PAM_STRERROR(__pamh, pam_retval));
+#ifdef PAM_TTY_KLUDGE
+       /*
+        * Some PAM modules (e.g. pam_time) require a TTY to operate,
+        * and will fail in various stupid ways if they don't get one.
+        * sshd doesn't set the tty until too late in the auth process and may
+        * not even need one (for tty-less connections)
+        * Kludge: Set a fake PAM_TTY
+        */
+       pam_retval = pam_set_item(__pamh, PAM_TTY, "NODEVssh");
+       if (pam_retval != PAM_SUCCESS)
+               fatal("PAM set tty failed[%d]: %.200s",
+                   pam_retval, PAM_STRERROR(__pamh, pam_retval));
+#endif /* PAM_TTY_KLUDGE */
+
+       fatal_add_cleanup(&do_pam_cleanup_proc, NULL);
+}
+
+/* Return list of PAM enviornment strings */
+char **fetch_pam_environment(void)
+{
+#ifdef HAVE_PAM_GETENVLIST
+       return(pam_getenvlist(__pamh));
+#else /* HAVE_PAM_GETENVLIST */
+       return(NULL);
+#endif /* HAVE_PAM_GETENVLIST */
+}
+
+/* Print any messages that have been generated during authentication */
+/* or account checking to stderr */
+void print_pam_messages(void)
+{
+       if (__pam_msg != NULL)
+               fputs(__pam_msg, stderr);
+}
+
+/* Append a message to buffer */
+void message_cat(char **p, const char *a)
+{
+       char *cp;
+       size_t new_len;
+
+       new_len = strlen(a);
+
+       if (*p) {
+               size_t len = strlen(*p);
+
+               *p = xrealloc(*p, new_len + len + 2);
+               cp = *p + len;
+       } else
+               *p = cp = xmalloc(new_len + 2);
+
+       memcpy(cp, a, new_len);
+       cp[new_len] = '\n';
+       cp[new_len + 1] = '\0';
+}
+
+#endif /* USE_PAM */
diff --git a/openssh/auth-pam.h b/openssh/auth-pam.h
new file mode 100644 (file)
index 0000000..30e4df5
--- /dev/null
@@ -0,0 +1,22 @@
+/* $Id$ */
+
+#include "includes.h"
+#ifdef USE_PAM
+
+#include <pwd.h> /* For struct passwd */
+
+void start_pam(const char *user);
+void finish_pam(void);
+int auth_pam_password(struct passwd *pw, const char *password);
+char **fetch_pam_environment(void);
+int do_pam_authenticate(int flags);
+int do_pam_account(char *username, char *remote_user);
+void do_pam_session(char *username, const char *ttyname);
+void do_pam_setcred(int init);
+void print_pam_messages(void);
+int is_pam_password_change_required(void);
+void do_pam_chauthtok(void);
+void do_pam_set_conv(struct pam_conv *);
+void message_cat(char **p, const char *a);
+
+#endif /* USE_PAM */
diff --git a/openssh/auth-passwd.c b/openssh/auth-passwd.c
new file mode 100644 (file)
index 0000000..988297c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Password authentication.  This file contains the functions to check whether
+ * the password is valid for the user.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 1999 Dug Song.  All rights reserved.
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-passwd.c,v 1.23 2001/06/26 16:15:23 dugsong Exp $");
+
+#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
+
+#include "packet.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+#include "auth.h"
+
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#endif
+#ifdef WITH_AIXAUTHENTICATE
+# include <login.h>
+#endif
+#ifdef __hpux
+# include <hpsecurity.h>
+# include <prot.h>
+#endif
+#ifdef HAVE_SCO_PROTECTED_PW
+# include <sys/security.h>
+# include <sys/audit.h>
+# include <prot.h>
+#endif /* HAVE_SCO_PROTECTED_PW */
+#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+# include <shadow.h>
+#endif
+#if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
+# include <sys/label.h>
+# include <sys/audit.h>
+# include <pwdadj.h>
+#endif
+#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
+# include "md5crypt.h"
+#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
+
+#ifdef HAVE_CYGWIN
+#undef ERROR
+#include <windows.h>
+#include <sys/cygwin.h>
+#define is_winnt       (GetVersion() < 0x80000000)
+#endif
+
+
+extern ServerOptions options;
+
+/*
+ * Tries to authenticate the user using password.  Returns true if
+ * authentication succeeds.
+ */
+int
+auth_password(Authctxt *authctxt, const char *password)
+{
+       struct passwd * pw = authctxt->pw;
+       char *encrypted_password;
+       char *pw_password;
+       char *salt;
+#ifdef __hpux
+       struct pr_passwd *spw;
+#endif
+#ifdef HAVE_SCO_PROTECTED_PW
+       struct pr_passwd *spw;
+#endif /* HAVE_SCO_PROTECTED_PW */
+#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+       struct spwd *spw;
+#endif
+#if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
+       struct passwd_adjunct *spw;
+#endif
+#ifdef WITH_AIXAUTHENTICATE
+       char *authmsg;
+       char *loginmsg;
+       int reenter = 1;
+#endif
+
+       /* deny if no user. */
+       if (pw == NULL)
+               return 0;
+#ifndef HAVE_CYGWIN
+       if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
+               return 0;
+#endif
+#ifdef HAVE_CYGWIN
+       /*
+        * Empty password is only possible on NT if the user has _really_
+        * an empty password and authentication is done, though.
+        */
+       if (!is_winnt)
+#endif
+       if (*password == '\0' && options.permit_empty_passwd == 0)
+               return 0;
+#ifdef KRB5
+       if (options.kerberos_authentication == 1) {
+               int ret = auth_krb5_password(authctxt, password);
+               if (ret == 1 || ret == 0)
+                       return ret;
+               /* Fall back to ordinary passwd authentication. */
+       }
+#endif
+#ifdef HAVE_CYGWIN
+       if (is_winnt) {
+               HANDLE hToken = cygwin_logon_user(pw, password);
+
+               if (hToken == INVALID_HANDLE_VALUE)
+                       return 0;
+               cygwin_set_impersonation_token(hToken);
+               return 1;
+       }
+#endif
+#ifdef WITH_AIXAUTHENTICATE
+       return (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0);
+#endif
+#ifdef KRB4
+       if (options.kerberos_authentication == 1) {
+               int ret = auth_krb4_password(authctxt, password);
+               if (ret == 1 || ret == 0)
+                       return ret;
+               /* Fall back to ordinary passwd authentication. */
+       }
+#endif
+#ifdef BSD_AUTH
+       if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
+           (char *)password) == 0)
+               return 0;
+       else
+               return 1;
+#endif
+       pw_password = pw->pw_passwd;
+
+       /*
+        * Various interfaces to shadow or protected password data
+        */
+#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+       spw = getspnam(pw->pw_name);
+       if (spw != NULL)
+               pw_password = spw->sp_pwdp;
+#endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */
+
+#ifdef HAVE_SCO_PROTECTED_PW
+       spw = getprpwnam(pw->pw_name);
+       if (spw != NULL)
+               pw_password = spw->ufld.fd_encrypt;
+#endif /* HAVE_SCO_PROTECTED_PW */
+
+#if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
+       if (issecure() && (spw = getpwanam(pw->pw_name)) != NULL)
+               pw_password = spw->pwa_passwd;
+#endif /* defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW) */
+
+#if defined(__hpux)
+       if (iscomsec() && (spw = getprpwnam(pw->pw_name)) != NULL)
+               pw_password = spw->ufld.fd_encrypt;
+#endif /* defined(__hpux) */
+
+       /* Check for users with no password. */
+       if ((password[0] == '\0') && (pw_password[0] == '\0'))
+               return 1;
+
+       if (pw_password[0] != '\0')
+               salt = pw_password;
+       else
+               salt = "xx";
+
+#ifdef HAVE_MD5_PASSWORDS
+       if (is_md5_salt(salt))
+               encrypted_password = md5_crypt(password, salt);
+       else
+               encrypted_password = crypt(password, salt);
+#else /* HAVE_MD5_PASSWORDS */
+# ifdef __hpux
+       if (iscomsec())
+               encrypted_password = bigcrypt(password, salt);
+       else
+               encrypted_password = crypt(password, salt);
+# else
+       encrypted_password = crypt(password, salt);
+# endif /* __hpux */
+#endif /* HAVE_MD5_PASSWORDS */
+
+       /* Authentication is accepted if the encrypted passwords are identical. */
+       return (strcmp(encrypted_password, pw_password) == 0);
+}
+#endif /* !USE_PAM && !HAVE_OSF_SIA */
diff --git a/openssh/auth-rh-rsa.c b/openssh/auth-rh-rsa.c
new file mode 100644 (file)
index 0000000..8a486b3
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Rhosts or /etc/hosts.equiv authentication combined with RSA host
+ * authentication.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-rh-rsa.c,v 1.26 2001/11/07 22:41:51 markus Exp $");
+
+#include "packet.h"
+#include "xmalloc.h"
+#include "uidswap.h"
+#include "log.h"
+#include "servconf.h"
+#include "key.h"
+#include "hostfile.h"
+#include "pathnames.h"
+#include "auth.h"
+#include "canohost.h"
+
+/*
+ * Tries to authenticate the user using the .rhosts file and the host using
+ * its host key.  Returns true if authentication succeeds.
+ */
+
+int
+auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key)
+{
+       extern ServerOptions options;
+       const char *canonical_hostname;
+       HostStatus host_status;
+       Key *client_key;
+
+       debug("Trying rhosts with RSA host authentication for client user %.100s", client_user);
+
+       if (pw == NULL || client_host_key == NULL)
+               return 0;
+
+       /* Check if we would accept it using rhosts authentication. */
+       if (!auth_rhosts(pw, client_user))
+               return 0;
+
+       canonical_hostname = get_canonical_hostname(
+           options.reverse_mapping_check);
+
+       debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);
+
+       /* wrap the RSA key into a 'generic' key */
+       client_key = key_new(KEY_RSA1);
+       BN_copy(client_key->rsa->e, client_host_key->e);
+       BN_copy(client_key->rsa->n, client_host_key->n);
+
+       host_status = check_key_in_hostfiles(pw, client_key, canonical_hostname,
+           _PATH_SSH_SYSTEM_HOSTFILE,
+           options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
+
+       key_free(client_key);
+
+       if (host_status != HOST_OK) {
+               debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
+               packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
+               return 0;
+       }
+       /* A matching host key was found and is known. */
+
+       /* Perform the challenge-response dialog with the client for the host key. */
+       if (!auth_rsa_challenge_dialog(client_host_key)) {
+               log("Client on %.800s failed to respond correctly to host authentication.",
+                   canonical_hostname);
+               return 0;
+       }
+       /*
+        * We have authenticated the user using .rhosts or /etc/hosts.equiv,
+        * and the host using RSA. We accept the authentication.
+        */
+
+       verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
+          pw->pw_name, client_user, canonical_hostname);
+       packet_send_debug("Rhosts with RSA host authentication accepted.");
+       return 1;
+}
diff --git a/openssh/auth-rhosts.c b/openssh/auth-rhosts.c
new file mode 100644 (file)
index 0000000..9ba64db
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Rhosts authentication.  This file contains code to check whether to admit
+ * the login based on rhosts authentication.  This file also processes
+ * /etc/hosts.equiv.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-rhosts.c,v 1.24 2001/06/23 15:12:17 itojun Exp $");
+
+#include "packet.h"
+#include "xmalloc.h"
+#include "uidswap.h"
+#include "pathnames.h"
+#include "log.h"
+#include "servconf.h"
+#include "canohost.h"
+#include "auth.h"
+
+/* import */
+extern ServerOptions options;
+
+/*
+ * This function processes an rhosts-style file (.rhosts, .shosts, or
+ * /etc/hosts.equiv).  This returns true if authentication can be granted
+ * based on the file, and returns zero otherwise.
+ */
+
+static int
+check_rhosts_file(const char *filename, const char *hostname,
+                 const char *ipaddr, const char *client_user,
+                 const char *server_user)
+{
+       FILE *f;
+       char buf[1024]; /* Must not be larger than host, user, dummy below. */
+
+       /* Open the .rhosts file, deny if unreadable */
+       f = fopen(filename, "r");
+       if (!f)
+               return 0;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               /* All three must be at least as big as buf to avoid overflows. */
+               char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
+               int negated;
+
+               for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (*cp == '#' || *cp == '\n' || !*cp)
+                       continue;
+
+               /*
+                * NO_PLUS is supported at least on OSF/1.  We skip it (we
+                * don't ever support the plus syntax).
+                */
+               if (strncmp(cp, "NO_PLUS", 7) == 0)
+                       continue;
+
+               /*
+                * This should be safe because each buffer is as big as the
+                * whole string, and thus cannot be overwritten.
+                */
+               switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
+               case 0:
+                       packet_send_debug("Found empty line in %.100s.", filename);
+                       continue;
+               case 1:
+                       /* Host name only. */
+                       strlcpy(userbuf, server_user, sizeof(userbuf));
+                       break;
+               case 2:
+                       /* Got both host and user name. */
+                       break;
+               case 3:
+                       packet_send_debug("Found garbage in %.100s.", filename);
+                       continue;
+               default:
+                       /* Weird... */
+                       continue;
+               }
+
+               host = hostbuf;
+               user = userbuf;
+               negated = 0;
+
+               /* Process negated host names, or positive netgroups. */
+               if (host[0] == '-') {
+                       negated = 1;
+                       host++;
+               } else if (host[0] == '+')
+                       host++;
+
+               if (user[0] == '-') {
+                       negated = 1;
+                       user++;
+               } else if (user[0] == '+')
+                       user++;
+
+               /* Check for empty host/user names (particularly '+'). */
+               if (!host[0] || !user[0]) {
+                       /* We come here if either was '+' or '-'. */
+                       packet_send_debug("Ignoring wild host/user names in %.100s.",
+                                         filename);
+                       continue;
+               }
+               /* Verify that host name matches. */
+               if (host[0] == '@') {
+                       if (!innetgr(host + 1, hostname, NULL, NULL) &&
+                           !innetgr(host + 1, ipaddr, NULL, NULL))
+                               continue;
+               } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
+                       continue;       /* Different hostname. */
+
+               /* Verify that user name matches. */
+               if (user[0] == '@') {
+                       if (!innetgr(user + 1, NULL, client_user, NULL))
+                               continue;
+               } else if (strcmp(user, client_user) != 0)
+                       continue;       /* Different username. */
+
+               /* Found the user and host. */
+               fclose(f);
+
+               /* If the entry was negated, deny access. */
+               if (negated) {
+                       packet_send_debug("Matched negative entry in %.100s.",
+                                         filename);
+                       return 0;
+               }
+               /* Accept authentication. */
+               return 1;
+       }
+
+       /* Authentication using this file denied. */
+       fclose(f);
+       return 0;
+}
+
+/*
+ * Tries to authenticate the user using the .shosts or .rhosts file. Returns
+ * true if authentication succeeds.  If ignore_rhosts is true, only
+ * /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
+ */
+
+int
+auth_rhosts(struct passwd *pw, const char *client_user)
+{
+       const char *hostname, *ipaddr;
+       int ret;
+
+       hostname = get_canonical_hostname(options.reverse_mapping_check);
+       ipaddr = get_remote_ipaddr();
+       ret = auth_rhosts2(pw, client_user, hostname, ipaddr);
+       return ret;
+}
+
+int
+auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
+    const char *ipaddr)
+{
+       char buf[1024];
+       struct stat st;
+       static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
+       u_int rhosts_file_index;
+
+       debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s",
+           client_user, hostname, ipaddr);
+
+       /* no user given */
+       if (pw == NULL)
+               return 0;
+
+       /* Switch to the user's uid. */
+       temporarily_use_uid(pw);
+       /*
+        * Quick check: if the user has no .shosts or .rhosts files, return
+        * failure immediately without doing costly lookups from name
+        * servers.
+        */
+       for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
+            rhosts_file_index++) {
+               /* Check users .rhosts or .shosts. */
+               snprintf(buf, sizeof buf, "%.500s/%.100s",
+                        pw->pw_dir, rhosts_files[rhosts_file_index]);
+               if (stat(buf, &st) >= 0)
+                       break;
+       }
+       /* Switch back to privileged uid. */
+       restore_uid();
+
+       /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
+       if (!rhosts_files[rhosts_file_index] &&
+           stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
+           stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
+               return 0;
+
+       /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
+       if (pw->pw_uid != 0) {
+               if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user,
+                                     pw->pw_name)) {
+                       packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
+                                         hostname, ipaddr);
+                       return 1;
+               }
+               if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
+                                     pw->pw_name)) {
+                       packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
+                                     hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
+                       return 1;
+               }
+       }
+       /*
+        * Check that the home directory is owned by root or the user, and is
+        * not group or world writable.
+        */
+       if (stat(pw->pw_dir, &st) < 0) {
+               log("Rhosts authentication refused for %.100s: no home directory %.200s",
+                   pw->pw_name, pw->pw_dir);
+               packet_send_debug("Rhosts authentication refused for %.100s: no home directory %.200s",
+                                 pw->pw_name, pw->pw_dir);
+               return 0;
+       }
+       if (options.strict_modes &&
+           ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+            (st.st_mode & 022) != 0)) {
+               log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
+                   pw->pw_name);
+               packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
+                                 pw->pw_name);
+               return 0;
+       }
+       /* Temporarily use the user's uid. */
+       temporarily_use_uid(pw);
+
+       /* Check all .rhosts files (currently .shosts and .rhosts). */
+       for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
+            rhosts_file_index++) {
+               /* Check users .rhosts or .shosts. */
+               snprintf(buf, sizeof buf, "%.500s/%.100s",
+                        pw->pw_dir, rhosts_files[rhosts_file_index]);
+               if (stat(buf, &st) < 0)
+                       continue;
+
+               /*
+                * Make sure that the file is either owned by the user or by
+                * root, and make sure it is not writable by anyone but the
+                * owner.  This is to help avoid novices accidentally
+                * allowing access to their account by anyone.
+                */
+               if (options.strict_modes &&
+                   ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+                    (st.st_mode & 022) != 0)) {
+                       log("Rhosts authentication refused for %.100s: bad modes for %.200s",
+                           pw->pw_name, buf);
+                       packet_send_debug("Bad file modes for %.200s", buf);
+                       continue;
+               }
+               /* Check if we have been configured to ignore .rhosts and .shosts files. */
+               if (options.ignore_rhosts) {
+                       packet_send_debug("Server has been configured to ignore %.100s.",
+                                         rhosts_files[rhosts_file_index]);
+                       continue;
+               }
+               /* Check if authentication is permitted by the file. */
+               if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
+                       packet_send_debug("Accepted by %.100s.",
+                                         rhosts_files[rhosts_file_index]);
+                       /* Restore the privileged uid. */
+                       restore_uid();
+                       return 1;
+               }
+       }
+
+       /* Restore the privileged uid. */
+       restore_uid();
+       return 0;
+}
diff --git a/openssh/auth-rsa.c b/openssh/auth-rsa.c
new file mode 100644 (file)
index 0000000..701d8bd
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * RSA-based authentication.  This code determines whether to admit a login
+ * based on RSA authentication.  This file also contains functions to check
+ * validity of the host key.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth-rsa.c,v 1.44 2001/07/23 18:14:58 stevesk Exp $");
+
+#include <openssl/rsa.h>
+#include <openssl/md5.h>
+
+#include "rsa.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "ssh1.h"
+#include "mpaux.h"
+#include "uidswap.h"
+#include "match.h"
+#include "auth-options.h"
+#include "pathnames.h"
+#include "log.h"
+#include "servconf.h"
+#include "auth.h"
+
+/* import */
+extern ServerOptions options;
+
+/*
+ * Session identifier that is used to bind key exchange and authentication
+ * responses to a particular session.
+ */
+extern u_char session_id[16];
+
+/*
+ * The .ssh/authorized_keys file contains public keys, one per line, in the
+ * following format:
+ *   options bits e n comment
+ * where bits, e and n are decimal numbers,
+ * and comment is any string of characters up to newline.  The maximum
+ * length of a line is 8000 characters.  See the documentation for a
+ * description of the options.
+ */
+
+/*
+ * Performs the RSA authentication challenge-response dialog with the client,
+ * and returns true (non-zero) if the client gave the correct answer to
+ * our challenge; returns zero if the client gives a wrong answer.
+ */
+
+int
+auth_rsa_challenge_dialog(RSA *pk)
+{
+       BIGNUM *challenge, *encrypted_challenge;
+       BN_CTX *ctx;
+       u_char buf[32], mdbuf[16], response[16];
+       MD5_CTX md;
+       u_int i;
+       int plen, len;
+
+       encrypted_challenge = BN_new();
+       challenge = BN_new();
+
+       /* Generate a random challenge. */
+       BN_rand(challenge, 256, 0, 0);
+       ctx = BN_CTX_new();
+       BN_mod(challenge, challenge, pk->n, ctx);
+       BN_CTX_free(ctx);
+
+       /* Encrypt the challenge with the public key. */
+       rsa_public_encrypt(encrypted_challenge, challenge, pk);
+
+       /* Send the encrypted challenge to the client. */
+       packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
+       packet_put_bignum(encrypted_challenge);
+       packet_send();
+       BN_clear_free(encrypted_challenge);
+       packet_write_wait();
+
+       /* Wait for a response. */
+       packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
+       packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
+       for (i = 0; i < 16; i++)
+               response[i] = packet_get_char();
+
+       /* The response is MD5 of decrypted challenge plus session id. */
+       len = BN_num_bytes(challenge);
+       if (len <= 0 || len > 32)
+               fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
+       memset(buf, 0, 32);
+       BN_bn2bin(challenge, buf + 32 - len);
+       MD5_Init(&md);
+       MD5_Update(&md, buf, 32);
+       MD5_Update(&md, session_id, 16);
+       MD5_Final(mdbuf, &md);
+       BN_clear_free(challenge);
+
+       /* Verify that the response is the original challenge. */
+       if (memcmp(response, mdbuf, 16) != 0) {
+               /* Wrong answer. */
+               return 0;
+       }
+       /* Correct answer. */
+       return 1;
+}
+
+/*
+ * Performs the RSA authentication dialog with the client.  This returns
+ * 0 if the client could not be authenticated, and 1 if authentication was
+ * successful.  This may exit if there is a serious protocol violation.
+ */
+
+int
+auth_rsa(struct passwd *pw, BIGNUM *client_n)
+{
+       char line[8192], *file;
+       int authenticated;
+       u_int bits;
+       FILE *f;
+       u_long linenum = 0;
+       struct stat st;
+       RSA *pk;
+
+       /* no user given */
+       if (pw == NULL)
+               return 0;
+
+       /* Temporarily use the user's uid. */
+       temporarily_use_uid(pw);
+
+       /* The authorized keys. */
+       file = authorized_keys_file(pw);
+       debug("trying public RSA key file %s", file);
+
+       /* Fail quietly if file does not exist */
+       if (stat(file, &st) < 0) {
+               /* Restore the privileged uid. */
+               restore_uid();
+               xfree(file);
+               return 0;
+       }
+       /* Open the file containing the authorized keys. */
+       f = fopen(file, "r");
+       if (!f) {
+               /* Restore the privileged uid. */
+               restore_uid();
+               packet_send_debug("Could not open %.900s for reading.", file);
+               packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
+               xfree(file);
+               return 0;
+       }
+       if (options.strict_modes &&
+           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+               xfree(file);
+               fclose(f);
+               log("Authentication refused: %s", line);
+               packet_send_debug("Authentication refused: %s", line);
+               restore_uid();
+               return 0;
+       }
+       /* Flag indicating whether authentication has succeeded. */
+       authenticated = 0;
+
+       pk = RSA_new();
+       pk->e = BN_new();
+       pk->n = BN_new();
+
+       /*
+        * Go though the accepted keys, looking for the current key.  If
+        * found, perform a challenge-response dialog to verify that the
+        * user really has the corresponding private key.
+        */
+       while (fgets(line, sizeof(line), f)) {
+               char *cp;
+               char *options;
+
+               linenum++;
+
+               /* Skip leading whitespace, empty and comment lines. */
+               for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '\n' || *cp == '#')
+                       continue;
+
+               /*
+                * Check if there are options for this key, and if so,
+                * save their starting address and skip the option part
+                * for now.  If there are no options, set the starting
+                * address to NULL.
+                */
+               if (*cp < '0' || *cp > '9') {
+                       int quoted = 0;
+                       options = cp;
+                       for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+                               if (*cp == '\\' && cp[1] == '"')
+                                       cp++;   /* Skip both */
+                               else if (*cp == '"')
+                                       quoted = !quoted;
+                       }
+               } else
+                       options = NULL;
+
+               /* Parse the key from the line. */
+               if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
+                       debug("%.100s, line %lu: non ssh1 key syntax",
+                           file, linenum);
+                       continue;
+               }
+               /* cp now points to the comment part. */
+
+               /* Check if the we have found the desired key (identified by its modulus). */
+               if (BN_cmp(pk->n, client_n) != 0)
+                       continue;
+
+               /* check the real bits  */
+               if (bits != BN_num_bits(pk->n))
+                       log("Warning: %s, line %lu: keysize mismatch: "
+                           "actual %d vs. announced %d.",
+                           file, linenum, BN_num_bits(pk->n), bits);
+
+               /* We have found the desired key. */
+               /*
+                * If our options do not allow this key to be used,
+                * do not send challenge.
+                */
+               if (!auth_parse_options(pw, options, file, linenum))
+                       continue;
+
+               /* Perform the challenge-response dialog for this key. */
+               if (!auth_rsa_challenge_dialog(pk)) {
+                       /* Wrong response. */
+                       verbose("Wrong response to RSA authentication challenge.");
+                       packet_send_debug("Wrong response to RSA authentication challenge.");
+                       continue;
+               }
+               /*
+                * Correct response.  The client has been successfully
+                * authenticated. Note that we have not yet processed the
+                * options; this will be reset if the options cause the
+                * authentication to be rejected.
+                * Break out of the loop if authentication was successful;
+                * otherwise continue searching.
+                */
+               authenticated = 1;
+               break;
+       }
+
+       /* Restore the privileged uid. */
+       restore_uid();
+
+       /* Close the file. */
+       xfree(file);
+       fclose(f);
+
+       RSA_free(pk);
+
+       if (authenticated)
+               packet_send_debug("RSA authentication accepted.");
+       else
+               auth_clear_options();
+
+       /* Return authentication result. */
+       return authenticated;
+}
diff --git a/openssh/auth-sia.c b/openssh/auth-sia.c
new file mode 100644 (file)
index 0000000..4e947cd
--- /dev/null
@@ -0,0 +1,107 @@
+#include "includes.h"
+
+#ifdef HAVE_OSF_SIA
+#include "ssh.h"
+#include "auth-sia.h"
+#include "log.h"
+#include "servconf.h"
+#include "canohost.h"
+
+#include <sia.h>
+#include <siad.h>
+#include <pwd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <string.h>
+
+extern ServerOptions options;
+extern int saved_argc;
+extern char **saved_argv;
+
+extern int errno;
+
+int
+auth_sia_password(char *user, char *pass)
+{
+       int ret;
+       SIAENTITY *ent = NULL;
+       const char *host;
+
+       host = get_canonical_hostname(options.reverse_mapping_check);
+
+       if (!user || !pass)
+               return(0);
+
+       if (sia_ses_init(&ent, saved_argc, saved_argv, host, user, NULL, 0,
+           NULL) != SIASUCCESS)
+               return(0);
+
+       if ((ret = sia_ses_authent(NULL, pass, ent)) != SIASUCCESS) {
+               error("couldn't authenticate %s from %s", user, host);
+               if (ret & SIASTOP)
+                       sia_ses_release(&ent);
+               return(0);
+       }
+
+       sia_ses_release(&ent);
+
+       return(1);
+}
+
+void
+session_setup_sia(char *user, char *tty)
+{
+       int ret;
+       struct passwd *pw;
+       SIAENTITY *ent = NULL;
+       const char *host;
+
+       host = get_canonical_hostname (options.reverse_mapping_check);
+
+       if (sia_ses_init(&ent, saved_argc, saved_argv, host, user, tty, 0,
+           NULL) != SIASUCCESS) {
+               error("sia_ses_init failed");
+               exit(1);
+       }
+
+       if ((pw = getpwnam(user)) == NULL) {
+               sia_ses_release(&ent);
+               error("getpwnam(%s) failed: %s", user, strerror(errno));
+               exit(1);
+       }
+       if (sia_make_entity_pwd(pw, ent) != SIASUCCESS) {
+               sia_ses_release(&ent);
+               error("sia_make_entity_pwd failed");
+               exit(1);
+       }
+
+       ent->authtype = SIA_A_NONE;
+       if (sia_ses_estab(sia_collect_trm, ent) != SIASUCCESS) {
+               error("couldn't establish session for %s from %s", user,
+                   host);
+               exit(1);
+       }
+
+       if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
+               sia_ses_release(&ent);
+               error("setpriority failed: %s", strerror (errno));
+               exit(1);
+       }
+
+       if (sia_ses_launch(sia_collect_trm, ent) != SIASUCCESS) {
+               error("couldn't launch session for %s from %s", user, host);
+               exit(1);
+       }
+       
+       sia_ses_release(&ent);
+
+       if (setreuid(geteuid(), geteuid()) < 0) {
+               error("setreuid failed: %s", strerror (errno));
+               exit(1);
+       }
+}
+
+#endif /* HAVE_OSF_SIA */
+
diff --git a/openssh/auth-sia.h b/openssh/auth-sia.h
new file mode 100644 (file)
index 0000000..eaa9333
--- /dev/null
@@ -0,0 +1,8 @@
+#include "includes.h"
+
+#ifdef HAVE_OSF_SIA
+
+int    auth_sia_password(char *user, char *pass);
+void   session_setup_sia(char *user, char *tty);
+
+#endif /* HAVE_OSF_SIA */
diff --git a/openssh/auth-skey.c b/openssh/auth-skey.c
new file mode 100644 (file)
index 0000000..f921fc1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: auth-skey.c,v 1.12 2001/05/18 14:13:28 markus Exp $");
+
+#ifdef SKEY
+
+#include <skey.h>
+
+#include "xmalloc.h"
+#include "auth.h"
+
+static void *
+skey_init_ctx(Authctxt *authctxt)
+{
+       return authctxt;
+}
+
+#define PROMPT "\nS/Key Password: "
+
+static int
+skey_query(void *ctx, char **name, char **infotxt, 
+    u_int* numprompts, char ***prompts, u_int **echo_on)
+{
+       Authctxt *authctxt = ctx;
+       char challenge[1024], *p;
+       int len;
+       struct skey skey;
+
+       if (skeychallenge(&skey, authctxt->user, challenge) == -1)
+               return -1;
+
+       *name       = xstrdup("");
+       *infotxt    = xstrdup("");
+       *numprompts = 1;
+       *prompts = xmalloc(*numprompts * sizeof(char*));
+       *echo_on = xmalloc(*numprompts * sizeof(u_int));
+       (*echo_on)[0] = 0;
+
+       len = strlen(challenge) + strlen(PROMPT) + 1;
+       p = xmalloc(len);
+       p[0] = '\0';
+       strlcat(p, challenge, len);
+       strlcat(p, PROMPT, len);
+       (*prompts)[0] = p;
+
+       return 0;
+}
+
+static int
+skey_respond(void *ctx, u_int numresponses, char **responses)
+{
+       Authctxt *authctxt = ctx;
+       if (authctxt->valid &&
+           numresponses == 1 && 
+           skey_haskey(authctxt->pw->pw_name) == 0 &&
+           skey_passcheck(authctxt->pw->pw_name, responses[0]) != -1)
+           return 0;
+       return -1;
+}
+
+static void
+skey_free_ctx(void *ctx)
+{
+       /* we don't have a special context */
+}
+
+KbdintDevice skey_device = {
+       "skey",
+       skey_init_ctx,
+       skey_query,
+       skey_respond,
+       skey_free_ctx
+};
+#endif /* SKEY */
diff --git a/openssh/auth.c b/openssh/auth.c
new file mode 100644 (file)
index 0000000..2bf877d
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth.c,v 1.29 2001/11/08 20:02:24 markus Exp $");
+
+#ifdef HAVE_LOGIN_H
+#include <login.h>
+#endif
+#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+#include <shadow.h>
+#endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */
+
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
+
+#include "xmalloc.h"
+#include "match.h"
+#include "groupaccess.h"
+#include "log.h"
+#include "servconf.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "canohost.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "uidswap.h"
+#include "tildexpand.h"
+
+/* import */
+extern ServerOptions options;
+
+/*
+ * Check if the user is allowed to log in via ssh. If user is listed
+ * in DenyUsers or one of user's groups is listed in DenyGroups, false
+ * will be returned. If AllowUsers isn't empty and user isn't listed
+ * there, or if AllowGroups isn't empty and one of user's groups isn't
+ * listed there, false will be returned.
+ * If the user's shell is not executable, false will be returned.
+ * Otherwise true is returned.
+ */
+int
+allowed_user(struct passwd * pw)
+{
+       struct stat st;
+       const char *hostname = NULL, *ipaddr = NULL;
+       char *shell;
+       int i;
+#ifdef WITH_AIXAUTHENTICATE
+       char *loginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
+#if !defined(USE_PAM) && defined(HAVE_SHADOW_H) && \
+       !defined(DISABLE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
+       struct spwd *spw;
+
+       /* Shouldn't be called if pw is NULL, but better safe than sorry... */
+       if (!pw || !pw->pw_name)
+               return 0;
+
+       spw = getspnam(pw->pw_name);
+       if (spw != NULL) {
+               int days = time(NULL) / 86400;
+
+               /* Check account expiry */
+               if ((spw->sp_expire >= 0) && (days > spw->sp_expire))
+                       return 0;
+
+               /* Check password expiry */
+               if ((spw->sp_lstchg >= 0) && (spw->sp_max >= 0) &&
+                   (days > (spw->sp_lstchg + spw->sp_max)))
+                       return 0;
+       }
+#else
+       /* Shouldn't be called if pw is NULL, but better safe than sorry... */
+       if (!pw || !pw->pw_name)
+               return 0;
+#endif
+
+       /*
+        * Get the shell from the password data.  An empty shell field is
+        * legal, and means /bin/sh.
+        */
+       shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
+
+       /* deny if shell does not exists or is not executable */
+       if (stat(shell, &st) != 0)
+               return 0;
+       if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
+               return 0;
+
+       if (options.num_deny_users > 0 || options.num_allow_users > 0) {
+               hostname = get_canonical_hostname(options.reverse_mapping_check);
+               ipaddr = get_remote_ipaddr();
+       }
+
+       /* Return false if user is listed in DenyUsers */
+       if (options.num_deny_users > 0) {
+               for (i = 0; i < options.num_deny_users; i++)
+                       if (match_user(pw->pw_name, hostname, ipaddr,
+                           options.deny_users[i]))
+                               return 0;
+       }
+       /* Return false if AllowUsers isn't empty and user isn't listed there */
+       if (options.num_allow_users > 0) {
+               for (i = 0; i < options.num_allow_users; i++)
+                       if (match_user(pw->pw_name, hostname, ipaddr,
+                           options.allow_users[i]))
+                               break;
+               /* i < options.num_allow_users iff we break for loop */
+               if (i >= options.num_allow_users)
+                       return 0;
+       }
+       if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
+               /* Get the user's group access list (primary and supplementary) */
+               if (ga_init(pw->pw_name, pw->pw_gid) == 0)
+                       return 0;
+
+               /* Return false if one of user's groups is listed in DenyGroups */
+               if (options.num_deny_groups > 0)
+                       if (ga_match(options.deny_groups,
+                           options.num_deny_groups)) {
+                               ga_free();
+                               return 0;
+                       }
+               /*
+                * Return false if AllowGroups isn't empty and one of user's groups
+                * isn't listed there
+                */
+               if (options.num_allow_groups > 0)
+                       if (!ga_match(options.allow_groups,
+                           options.num_allow_groups)) {
+                               ga_free();
+                               return 0;
+                       }
+               ga_free();
+       }
+
+#ifdef WITH_AIXAUTHENTICATE
+       if (loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &loginmsg) != 0) {
+               if (loginmsg && *loginmsg) {
+                       /* Remove embedded newlines (if any) */
+                       char *p;
+                       for (p = loginmsg; *p; p++) {
+                               if (*p == '\n')
+                                       *p = ' ';
+                       }
+                       /* Remove trailing newline */
+                       *--p = '\0';
+                       log("Login restricted for %s: %.100s", pw->pw_name, loginmsg);
+               }
+               return 0;
+       }
+#endif /* WITH_AIXAUTHENTICATE */
+
+       /* We found no reason not to let this user try to log on... */
+       return 1;
+}
+
+Authctxt *
+authctxt_new(void)
+{
+       Authctxt *authctxt = xmalloc(sizeof(*authctxt));
+       memset(authctxt, 0, sizeof(*authctxt));
+       return authctxt;
+}
+
+void
+auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
+{
+       void (*authlog) (const char *fmt,...) = verbose;
+       char *authmsg;
+
+       /* Raise logging level */
+       if (authenticated == 1 ||
+           !authctxt->valid ||
+           authctxt->failures >= AUTH_FAIL_LOG ||
+           strcmp(method, "password") == 0)
+               authlog = log;
+
+       if (authctxt->postponed)
+               authmsg = "Postponed";
+       else
+               authmsg = authenticated ? "Accepted" : "Failed";
+
+       authlog("%s %s for %s%.100s from %.200s port %d%s",
+           authmsg,
+           method,
+           authctxt->valid ? "" : "illegal user ",
+           authctxt->user,
+           get_remote_ipaddr(),
+           get_remote_port(),
+           info);
+}
+
+/*
+ * Check whether root logins are disallowed.
+ */
+int
+auth_root_allowed(char *method)
+{
+       switch (options.permit_root_login) {
+       case PERMIT_YES:
+               return 1;
+               break;
+       case PERMIT_NO_PASSWD:
+               if (strcmp(method, "password") != 0)
+                       return 1;
+               break;
+       case PERMIT_FORCED_ONLY:
+               if (forced_command) {
+                       log("Root login accepted for forced command.");
+                       return 1;
+               }
+               break;
+       }
+       log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
+       return 0;
+}
+
+
+/*
+ * Given a template and a passwd structure, build a filename
+ * by substituting % tokenised options. Currently, %% becomes '%',
+ * %h becomes the home directory and %u the username.
+ *
+ * This returns a buffer allocated by xmalloc.
+ */
+char *
+expand_filename(const char *filename, struct passwd *pw)
+{
+       Buffer buffer;
+       char *file;
+       const char *cp;
+
+       /*
+        * Build the filename string in the buffer by making the appropriate
+        * substitutions to the given file name.
+        */
+       buffer_init(&buffer);
+       for (cp = filename; *cp; cp++) {
+               if (cp[0] == '%' && cp[1] == '%') {
+                       buffer_append(&buffer, "%", 1);
+                       cp++;
+                       continue;
+               }
+               if (cp[0] == '%' && cp[1] == 'h') {
+                       buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
+                       cp++;
+                       continue;
+               }
+               if (cp[0] == '%' && cp[1] == 'u') {
+                       buffer_append(&buffer, pw->pw_name,
+                            strlen(pw->pw_name));
+                       cp++;
+                       continue;
+               }
+               buffer_append(&buffer, cp, 1);
+       }
+       buffer_append(&buffer, "\0", 1);
+
+       /*
+        * Ensure that filename starts anchored. If not, be backward
+        * compatible and prepend the '%h/'
+        */
+       file = xmalloc(MAXPATHLEN);
+       cp = buffer_ptr(&buffer);
+       if (*cp != '/')
+               snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
+       else
+               strlcpy(file, cp, MAXPATHLEN);
+
+       buffer_free(&buffer);
+       return file;
+}
+
+char *
+authorized_keys_file(struct passwd *pw)
+{
+       return expand_filename(options.authorized_keys_file, pw);
+}
+
+char *
+authorized_keys_file2(struct passwd *pw)
+{
+       return expand_filename(options.authorized_keys_file2, pw);
+}
+
+/* return ok if key exists in sysfile or userfile */
+HostStatus
+check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
+    const char *sysfile, const char *userfile)
+{
+       Key *found;
+       char *user_hostfile;
+       struct stat st;
+       int host_status;
+
+       /* Check if we know the host and its host key. */
+       found = key_new(key->type);
+       host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
+
+       if (host_status != HOST_OK && userfile != NULL) {
+               user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
+               if (options.strict_modes &&
+                   (stat(user_hostfile, &st) == 0) &&
+                   ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+                    (st.st_mode & 022) != 0)) {
+                       log("Authentication refused for %.100s: "
+                           "bad owner or modes for %.200s",
+                           pw->pw_name, user_hostfile);
+               } else {
+                       temporarily_use_uid(pw);
+                       host_status = check_host_in_hostfile(user_hostfile,
+                           host, key, found, NULL);
+                       restore_uid();
+               }
+               xfree(user_hostfile);
+       }
+       key_free(found);
+
+       debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
+           "ok" : "not found", host);
+       return host_status;
+}
+
+
+/*
+ * Check a given file for security. This is defined as all components
+ * of the path to the file must either be owned by either the owner of
+ * of the file or root and no directories must be group or world writable.
+ *
+ * XXX Should any specific check be done for sym links ?
+ *
+ * Takes an open file descriptor, the file name, a uid and and
+ * error buffer plus max size as arguments.
+ *
+ * Returns 0 on success and -1 on failure
+ */
+int
+secure_filename(FILE *f, const char *file, struct passwd *pw,
+    char *err, size_t errlen)
+{
+       uid_t uid = pw->pw_uid;
+       char buf[MAXPATHLEN], homedir[MAXPATHLEN];
+       char *cp;
+       struct stat st;
+
+       if (realpath(file, buf) == NULL) {
+               snprintf(err, errlen, "realpath %s failed: %s", file,
+                   strerror(errno));
+               return -1;
+       }
+       if (realpath(pw->pw_dir, homedir) == NULL) {
+               snprintf(err, errlen, "realpath %s failed: %s", pw->pw_dir,
+                   strerror(errno));
+               return -1;
+       }
+
+       /* check the open file to avoid races */
+       if (fstat(fileno(f), &st) < 0 ||
+           (st.st_uid != 0 && st.st_uid != uid) ||
+           (st.st_mode & 022) != 0) {
+               snprintf(err, errlen, "bad ownership or modes for file %s",
+                   buf);
+               return -1;
+       }
+
+       /* for each component of the canonical path, walking upwards */
+       for (;;) {
+               if ((cp = dirname(buf)) == NULL) {
+                       snprintf(err, errlen, "dirname() failed");
+                       return -1;
+               }
+               strlcpy(buf, cp, sizeof(buf));
+
+               debug3("secure_filename: checking '%s'", buf);
+               if (stat(buf, &st) < 0 ||
+                   (st.st_uid != 0 && st.st_uid != uid) ||
+                   (st.st_mode & 022) != 0) {
+                       snprintf(err, errlen, 
+                           "bad ownership or modes for directory %s", buf);
+                       return -1;
+               }
+
+               /* If are passed the homedir then we can stop */
+               if (strcmp(homedir, buf) == 0) {
+                       debug3("secure_filename: terminating check at '%s'",
+                           buf);
+                       break;
+               }
+               /*
+                * dirname should always complete with a "/" path,
+                * but we can be paranoid and check for "." too
+                */
+               if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
+                       break;
+       }
+       return 0;
+}
diff --git a/openssh/auth.h b/openssh/auth.h
new file mode 100644 (file)
index 0000000..edfc9fb
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $OpenBSD: auth.h,v 1.22 2001/06/26 17:27:22 markus Exp $
+ */
+#ifndef AUTH_H
+#define AUTH_H
+
+#include "key.h"
+#include "hostfile.h"
+#include <openssl/rsa.h>
+
+#ifdef HAVE_LOGIN_CAP
+#include <login_cap.h>
+#endif
+#ifdef BSD_AUTH
+#include <bsd_auth.h>
+#endif
+#ifdef KRB5
+#include <krb5.h>
+#endif
+
+typedef struct Authctxt Authctxt;
+typedef struct KbdintDevice KbdintDevice;
+
+struct Authctxt {
+       int              success;
+       int              postponed;
+       int              valid;
+       int              attempt;
+       int              failures;
+       char            *user;
+       char            *service;
+       struct passwd   *pw;
+       char            *style;
+       void            *kbdintctxt;
+#ifdef BSD_AUTH
+       auth_session_t  *as;
+#endif
+#ifdef KRB4
+       char            *krb4_ticket_file;
+#endif
+#ifdef KRB5
+       krb5_context     krb5_ctx;
+       krb5_auth_context krb5_auth_ctx;
+       krb5_ccache      krb5_fwd_ccache;
+       krb5_principal   krb5_user;
+       char            *krb5_ticket_file;
+#endif
+};
+
+/*
+ * Keyboard interactive device:
+ * init_ctx    returns: non NULL upon success 
+ * query       returns: 0 - success, otherwise failure 
+ * respond     returns: 0 - success, 1 - need further interaction,
+ *             otherwise - failure
+ */
+struct KbdintDevice
+{
+       const char *name;
+       void*   (*init_ctx)     __P((Authctxt*));
+       int     (*query)        __P((void *ctx, char **name, char **infotxt,
+                               u_int *numprompts, char ***prompts,
+                               u_int **echo_on));
+       int     (*respond)      __P((void *ctx, u_int numresp, char **responses));
+       void    (*free_ctx)     __P((void *ctx));
+};
+
+int     auth_rhosts(struct passwd *, const char *);
+int
+auth_rhosts2(struct passwd *, const char *, const char *, const char *);
+
+int     auth_rhosts_rsa(struct passwd *, const char *, RSA *);
+int      auth_password(Authctxt *, const char *);
+int      auth_rsa(struct passwd *, BIGNUM *);
+int      auth_rsa_read_key(char **, u_int *, BIGNUM *, BIGNUM *);
+int      auth_rsa_challenge_dialog(RSA *);
+
+#ifdef KRB4
+#include <krb.h>
+int     auth_krb4(Authctxt *, KTEXT, char **);
+int    auth_krb4_password(Authctxt *, const char *);
+void    krb4_cleanup_proc(void *);
+
+#ifdef AFS
+#include <kafs.h>
+int     auth_krb4_tgt(Authctxt *, const char *);
+int     auth_afs_token(Authctxt *, const char *);
+#endif /* AFS */
+
+#endif /* KRB4 */
+
+#ifdef KRB5
+int    auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client);
+int    auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
+int    auth_krb5_password(Authctxt *authctxt, const char *password);
+void   krb5_cleanup_proc(void *authctxt);
+#endif /* KRB5 */
+
+#include "auth-pam.h"
+#include "auth2-pam.h"
+
+void   do_authentication(void);
+void   do_authentication2(void);
+
+Authctxt *authctxt_new(void);
+void   auth_log(Authctxt *, int, char *, char *);
+void   userauth_finish(Authctxt *, int, char *);
+int    auth_root_allowed(char *);
+
+int    auth2_challenge(Authctxt *, char *);
+
+int    allowed_user(struct passwd *);
+
+char   *get_challenge(Authctxt *);
+int    verify_response(Authctxt *, const char *);
+
+struct passwd * auth_get_user(void);
+
+char   *expand_filename(const char *, struct passwd *);
+char   *authorized_keys_file(struct passwd *);
+char   *authorized_keys_file2(struct passwd *);
+
+int
+secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
+
+HostStatus
+check_key_in_hostfiles(struct passwd *, Key *, const char *,
+    const char *, const char *);
+
+#define AUTH_FAIL_MAX 6
+#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
+#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
+
+#endif
diff --git a/openssh/auth1.c b/openssh/auth1.c
new file mode 100644 (file)
index 0000000..1fbfad9
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth1.c,v 1.25 2001/06/26 16:15:23 dugsong Exp $");
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh1.h"
+#include "packet.h"
+#include "buffer.h"
+#include "mpaux.h"
+#include "log.h"
+#include "servconf.h"
+#include "compat.h"
+#include "auth.h"
+#include "session.h"
+#include "misc.h"
+#include "uidswap.h"
+
+/* import */
+extern ServerOptions options;
+
+/*
+ * convert ssh auth msg type into description
+ */
+static char *
+get_authname(int type)
+{
+       static char buf[1024];
+       switch (type) {
+       case SSH_CMSG_AUTH_PASSWORD:
+               return "password";
+       case SSH_CMSG_AUTH_RSA:
+               return "rsa";
+       case SSH_CMSG_AUTH_RHOSTS_RSA:
+               return "rhosts-rsa";
+       case SSH_CMSG_AUTH_RHOSTS:
+               return "rhosts";
+       case SSH_CMSG_AUTH_TIS:
+       case SSH_CMSG_AUTH_TIS_RESPONSE:
+               return "challenge-response";
+#if defined(KRB4) || defined(KRB5)
+       case SSH_CMSG_AUTH_KERBEROS:
+               return "kerberos";
+#endif
+       }
+       snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
+       return buf;
+}
+
+/*
+ * read packets, try to authenticate the user and
+ * return only if authentication is successful
+ */
+static void
+do_authloop(Authctxt *authctxt)
+{
+       int authenticated = 0;
+       u_int bits;
+       RSA *client_host_key;
+       BIGNUM *n;
+       char *client_user, *password;
+       char info[1024];
+       u_int dlen;
+       int plen, nlen, elen;
+       u_int ulen;
+       int type = 0;
+       struct passwd *pw = authctxt->pw;
+
+       debug("Attempting authentication for %s%.100s.",
+            authctxt->valid ? "" : "illegal user ", authctxt->user);
+
+       /* If the user has no password, accept authentication immediately. */
+       if (options.password_authentication &&
+#if defined(KRB4) || defined(KRB5)
+           (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
+#endif
+#ifdef USE_PAM
+           auth_pam_password(pw, "")) {
+#elif defined(HAVE_OSF_SIA)
+           0) {
+#else
+           auth_password(authctxt, "")) {
+#endif
+               auth_log(authctxt, 1, "without authentication", "");
+               return;
+       }
+
+       /* Indicate that authentication is needed. */
+       packet_start(SSH_SMSG_FAILURE);
+       packet_send();
+       packet_write_wait();
+
+       client_user = NULL;
+
+       for (;;) {
+               /* default to fail */
+               authenticated = 0;
+
+               info[0] = '\0';
+
+               /* Get a packet from the client. */
+               type = packet_read(&plen);
+
+               /* Process the packet. */
+               switch (type) {
+
+#if defined(KRB4) || defined(KRB5)
+               case SSH_CMSG_AUTH_KERBEROS:
+                       if (!options.kerberos_authentication) {
+                               verbose("Kerberos authentication disabled.");
+                       } else {
+                               char *kdata = packet_get_string(&dlen);
+                               
+                               packet_integrity_check(plen, 4 + dlen, type);
+                               
+                               if (kdata[0] == 4) { /* KRB_PROT_VERSION */
+#ifdef KRB4
+                                       KTEXT_ST tkt;
+                                       
+                                       tkt.length = dlen;
+                                       if (tkt.length < MAX_KTXT_LEN)
+                                               memcpy(tkt.dat, kdata, tkt.length);
+                                       
+                                       if (auth_krb4(authctxt, &tkt, &client_user)) {
+                                               authenticated = 1;
+                                               snprintf(info, sizeof(info),
+                                                   " tktuser %.100s",
+                                                   client_user);
+                                       }
+#endif /* KRB4 */
+                               } else {
+#ifdef KRB5
+                                       krb5_data tkt;
+                                       tkt.length = dlen;
+                                       tkt.data = kdata;
+                                       
+                                       if (auth_krb5(authctxt, &tkt, &client_user)) {
+                                               authenticated = 1;
+                                               snprintf(info, sizeof(info),
+                                                   " tktuser %.100s",
+                                                   client_user);
+                                       }
+#endif /* KRB5 */
+                               }
+                               xfree(kdata);
+                       }
+                       break;
+#endif /* KRB4 || KRB5 */
+                       
+#if defined(AFS) || defined(KRB5)
+                       /* XXX - punt on backward compatibility here. */
+               case SSH_CMSG_HAVE_KERBEROS_TGT:
+                       packet_send_debug("Kerberos TGT passing disabled before authentication.");
+                       break;
+#ifdef AFS
+               case SSH_CMSG_HAVE_AFS_TOKEN:
+                       packet_send_debug("AFS token passing disabled before authentication.");
+                       break;
+#endif /* AFS */
+#endif /* AFS || KRB5 */
+                       
+               case SSH_CMSG_AUTH_RHOSTS:
+                       if (!options.rhosts_authentication) {
+                               verbose("Rhosts authentication disabled.");
+                               break;
+                       }
+                       /*
+                        * Get client user name.  Note that we just have to
+                        * trust the client; this is one reason why rhosts
+                        * authentication is insecure. (Another is
+                        * IP-spoofing on a local network.)
+                        */
+                       client_user = packet_get_string(&ulen);
+                       packet_integrity_check(plen, 4 + ulen, type);
+
+                       /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
+                       authenticated = auth_rhosts(pw, client_user);
+
+                       snprintf(info, sizeof info, " ruser %.100s", client_user);
+                       break;
+
+               case SSH_CMSG_AUTH_RHOSTS_RSA:
+                       if (!options.rhosts_rsa_authentication) {
+                               verbose("Rhosts with RSA authentication disabled.");
+                               break;
+                       }
+                       /*
+                        * Get client user name.  Note that we just have to
+                        * trust the client; root on the client machine can
+                        * claim to be any user.
+                        */
+                       client_user = packet_get_string(&ulen);
+
+                       /* Get the client host key. */
+                       client_host_key = RSA_new();
+                       if (client_host_key == NULL)
+                               fatal("RSA_new failed");
+                       client_host_key->e = BN_new();
+                       client_host_key->n = BN_new();
+                       if (client_host_key->e == NULL || client_host_key->n == NULL)
+                               fatal("BN_new failed");
+                       bits = packet_get_int();
+                       packet_get_bignum(client_host_key->e, &elen);
+                       packet_get_bignum(client_host_key->n, &nlen);
+
+                       if (bits != BN_num_bits(client_host_key->n))
+                               verbose("Warning: keysize mismatch for client_host_key: "
+                                   "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
+                       packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+
+                       authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
+                       RSA_free(client_host_key);
+
+                       snprintf(info, sizeof info, " ruser %.100s", client_user);
+                       break;
+
+               case SSH_CMSG_AUTH_RSA:
+                       if (!options.rsa_authentication) {
+                               verbose("RSA authentication disabled.");
+                               break;
+                       }
+                       /* RSA authentication requested. */
+                       n = BN_new();
+                       packet_get_bignum(n, &nlen);
+                       packet_integrity_check(plen, nlen, type);
+                       authenticated = auth_rsa(pw, n);
+                       BN_clear_free(n);
+                       break;
+
+               case SSH_CMSG_AUTH_PASSWORD:
+                       if (!options.password_authentication) {
+                               verbose("Password authentication disabled.");
+                               break;
+                       }
+                       /*
+                        * Read user password.  It is in plain text, but was
+                        * transmitted over the encrypted channel so it is
+                        * not visible to an outside observer.
+                        */
+                       password = packet_get_string(&dlen);
+                       packet_integrity_check(plen, 4 + dlen, type);
+
+#ifdef USE_PAM
+                       /* Do PAM auth with password */
+                       authenticated = auth_pam_password(pw, password);
+#elif defined(HAVE_OSF_SIA)
+                       /* Do SIA auth with password */
+                       authenticated = auth_sia_password(authctxt->user, 
+                           password);
+#else /* !USE_PAM && !HAVE_OSF_SIA */
+                       /* Try authentication with the password. */
+                       authenticated = auth_password(authctxt, password);
+#endif /* USE_PAM */
+
+                       memset(password, 0, strlen(password));
+                       xfree(password);
+                       break;
+
+               case SSH_CMSG_AUTH_TIS:
+                       debug("rcvd SSH_CMSG_AUTH_TIS");
+                       if (options.challenge_response_authentication == 1) {
+                               char *challenge = get_challenge(authctxt);
+                               if (challenge != NULL) {
+                                       debug("sending challenge '%s'", challenge);
+                                       packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+                                       packet_put_cstring(challenge);
+                                       xfree(challenge);
+                                       packet_send();
+                                       packet_write_wait();
+                                       continue;
+                               }
+                       }
+                       break;
+               case SSH_CMSG_AUTH_TIS_RESPONSE:
+                       debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
+                       if (options.challenge_response_authentication == 1) {
+                               char *response = packet_get_string(&dlen);
+                               debug("got response '%s'", response);
+                               packet_integrity_check(plen, 4 + dlen, type);
+                               authenticated = verify_response(authctxt, response);
+                               memset(response, 'r', dlen);
+                               xfree(response);
+                       }
+                       break;
+
+               default:
+                       /*
+                        * Any unknown messages will be ignored (and failure
+                        * returned) during authentication.
+                        */
+                       log("Unknown message during authentication: type %d", type);
+                       break;
+               }
+#ifdef BSD_AUTH
+               if (authctxt->as) {
+                       auth_close(authctxt->as);
+                       authctxt->as = NULL;
+               }
+#endif
+               if (!authctxt->valid && authenticated)
+                       fatal("INTERNAL ERROR: authenticated invalid user %s",
+                           authctxt->user);
+
+#ifdef HAVE_CYGWIN
+               if (authenticated &&
+                   !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,pw->pw_uid)) {
+                       packet_disconnect("Authentication rejected for uid %d.",
+                       (int)pw->pw_uid);
+                       authenticated = 0;
+               }
+#else
+               /* Special handling for root */
+               if (authenticated && authctxt->pw->pw_uid == 0 &&
+                   !auth_root_allowed(get_authname(type)))
+                       authenticated = 0;
+#endif
+#ifdef USE_PAM
+               if (authenticated && !do_pam_account(pw->pw_name, client_user))
+                       authenticated = 0;
+#endif
+
+               /* Log before sending the reply */
+               auth_log(authctxt, authenticated, get_authname(type), info);
+
+               if (client_user != NULL) {
+                       xfree(client_user);
+                       client_user = NULL;
+               }
+
+               if (authenticated)
+                       return;
+
+               if (authctxt->failures++ > AUTH_FAIL_MAX) {
+#ifdef WITH_AIXAUTHENTICATE
+                       loginfailed(authctxt->user,
+                           get_canonical_hostname(options.reverse_mapping_check),
+                           "ssh");
+#endif /* WITH_AIXAUTHENTICATE */
+                       packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+               }
+
+               packet_start(SSH_SMSG_FAILURE);
+               packet_send();
+               packet_write_wait();
+       }
+}
+
+/*
+ * Performs authentication of an incoming connection.  Session key has already
+ * been exchanged and encryption is enabled.
+ */
+void
+do_authentication()
+{
+       Authctxt *authctxt;
+       struct passwd *pw;
+       int plen;
+       u_int ulen;
+       char *p, *user, *style = NULL;
+
+       /* Get the name of the user that we wish to log in as. */
+       packet_read_expect(&plen, SSH_CMSG_USER);
+
+       /* Get the user name. */
+       user = packet_get_string(&ulen);
+       packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
+
+       if ((style = strchr(user, ':')) != NULL)
+               *style++ = '\0';
+
+       /* XXX - SSH.com Kerberos v5 braindeath. */
+       if ((p = strchr(user, '@')) != NULL)
+               *p = '\0';
+       
+       authctxt = authctxt_new();
+       authctxt->user = user;
+       authctxt->style = style;
+
+       /* Verify that the user is a valid user. */
+       pw = getpwnam(user);
+       if (pw && allowed_user(pw)) {
+               authctxt->valid = 1;
+               pw = pwcopy(pw);
+       } else {
+               debug("do_authentication: illegal user %s", user);
+               pw = NULL;
+       }
+       authctxt->pw = pw;
+
+       setproctitle("%s", pw ? user : "unknown");
+
+#ifdef USE_PAM
+       if (pw)
+               start_pam(user);
+#endif
+
+       /*
+        * If we are not running as root, the user must have the same uid as
+        * the server. (Unless you are running Windows)
+        */
+#ifndef HAVE_CYGWIN
+       if (getuid() != 0 && pw && pw->pw_uid != getuid())
+               packet_disconnect("Cannot change user when server not running as root.");
+#endif
+
+       /*
+        * Loop until the user has been authenticated or the connection is
+        * closed, do_authloop() returns only if authentication is successful
+        */
+       do_authloop(authctxt);
+
+       /* The user has been authenticated and accepted. */
+       packet_start(SSH_SMSG_SUCCESS);
+       packet_send();
+       packet_write_wait();
+
+       /* Perform session preparation. */
+       do_authenticated(authctxt);
+}
diff --git a/openssh/auth2-chall.c b/openssh/auth2-chall.c
new file mode 100644 (file)
index 0000000..5e6a691
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2001 Per Allansson.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: auth2-chall.c,v 1.8 2001/09/27 15:31:17 markus Exp $");
+
+#include "ssh2.h"
+#include "auth.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "dispatch.h"
+#include "auth.h"
+#include "log.h"
+
+static int auth2_challenge_start(Authctxt *);
+static int send_userauth_info_request(Authctxt *);
+static void input_userauth_info_response(int, int, void *);
+
+#ifdef BSD_AUTH
+extern KbdintDevice bsdauth_device;
+#else
+#ifdef SKEY
+extern KbdintDevice skey_device;
+#endif
+#endif
+
+KbdintDevice *devices[] = {
+#ifdef BSD_AUTH
+       &bsdauth_device,
+#else
+#ifdef SKEY
+       &skey_device,
+#endif
+#endif
+       NULL
+};
+
+typedef struct KbdintAuthctxt KbdintAuthctxt;
+struct KbdintAuthctxt
+{
+       char *devices;
+       void *ctxt;
+       KbdintDevice *device;
+};
+
+static KbdintAuthctxt *
+kbdint_alloc(const char *devs)
+{
+       KbdintAuthctxt *kbdintctxt;
+       int i;
+       char buf[1024];
+
+       kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
+       if (strcmp(devs, "") == 0) {
+               buf[0] = '\0';
+               for (i = 0; devices[i]; i++) {
+                       if (i != 0)
+                               strlcat(buf, ",", sizeof(buf));
+                       strlcat(buf, devices[i]->name, sizeof(buf));
+               }
+               debug("kbdint_alloc: devices '%s'", buf);
+               kbdintctxt->devices = xstrdup(buf);
+       } else {
+               kbdintctxt->devices = xstrdup(devs);
+       }
+       kbdintctxt->ctxt = NULL;
+       kbdintctxt->device = NULL;
+
+       return kbdintctxt;
+}
+static void
+kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
+{
+       if (kbdintctxt->ctxt) {
+               kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
+               kbdintctxt->ctxt = NULL;
+       }
+       kbdintctxt->device = NULL;
+}
+static void
+kbdint_free(KbdintAuthctxt *kbdintctxt)
+{
+       if (kbdintctxt->device)
+               kbdint_reset_device(kbdintctxt);
+       if (kbdintctxt->devices) {
+               xfree(kbdintctxt->devices);
+               kbdintctxt->devices = NULL;
+       }
+       xfree(kbdintctxt);
+}
+/* get next device */
+static int
+kbdint_next_device(KbdintAuthctxt *kbdintctxt)
+{
+       size_t len;
+       char *t;
+       int i;
+
+       if (kbdintctxt->device)
+               kbdint_reset_device(kbdintctxt);
+       do {
+               len = kbdintctxt->devices ?
+                   strcspn(kbdintctxt->devices, ",") : 0;
+
+               if (len == 0)
+                       break;
+               for (i = 0; devices[i]; i++)
+                       if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
+                               kbdintctxt->device = devices[i];
+               t = kbdintctxt->devices;
+               kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
+               xfree(t);
+               debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
+                  kbdintctxt->devices : "<empty>");
+       } while (kbdintctxt->devices && !kbdintctxt->device);
+
+       return kbdintctxt->device ? 1 : 0;
+}
+
+/*
+ * try challenge-response, set authctxt->postponed if we have to
+ * wait for the response.
+ */
+int
+auth2_challenge(Authctxt *authctxt, char *devs)
+{
+       debug("auth2_challenge: user=%s devs=%s",
+           authctxt->user ? authctxt->user : "<nouser>",
+           devs ? devs : "<no devs>");
+
+       if (authctxt->user == NULL || !devs)
+               return 0;
+       if (authctxt->kbdintctxt == NULL) 
+               authctxt->kbdintctxt = kbdint_alloc(devs);
+       return auth2_challenge_start(authctxt);
+}
+
+/* side effect: sets authctxt->postponed if a reply was sent*/
+static int
+auth2_challenge_start(Authctxt *authctxt)
+{
+       KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
+
+       debug2("auth2_challenge_start: devices %s",
+           kbdintctxt->devices ?  kbdintctxt->devices : "<empty>");
+
+       if (kbdint_next_device(kbdintctxt) == 0) {
+               kbdint_free(kbdintctxt);
+               authctxt->kbdintctxt = NULL;
+               return 0;
+       }
+       debug("auth2_challenge_start: trying authentication method '%s'",
+           kbdintctxt->device->name);
+
+       if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
+               kbdint_free(kbdintctxt);
+               authctxt->kbdintctxt = NULL;
+               return 0;
+       }
+       if (send_userauth_info_request(authctxt) == 0) {
+               kbdint_free(kbdintctxt);
+               authctxt->kbdintctxt = NULL;
+               return 0;
+       }
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
+           &input_userauth_info_response);
+
+       authctxt->postponed = 1;
+       return 0;
+}
+
+static int
+send_userauth_info_request(Authctxt *authctxt)
+{
+       KbdintAuthctxt *kbdintctxt;
+       char *name, *instr, **prompts;
+       int i;
+       u_int numprompts, *echo_on;
+
+       kbdintctxt = authctxt->kbdintctxt;
+       if (kbdintctxt->device->query(kbdintctxt->ctxt,
+           &name, &instr, &numprompts, &prompts, &echo_on))
+               return 0;
+
+       packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
+       packet_put_cstring(name);
+       packet_put_cstring(instr);
+       packet_put_cstring("");         /* language not used */
+       packet_put_int(numprompts);
+       for (i = 0; i < numprompts; i++) {
+               packet_put_cstring(prompts[i]);
+               packet_put_char(echo_on[i]);
+       }
+       packet_send();
+       packet_write_wait();
+
+       for (i = 0; i < numprompts; i++)
+               xfree(prompts[i]);
+       xfree(prompts);
+       xfree(echo_on);
+       xfree(name);
+       xfree(instr);
+       return 1;
+}
+
+static void
+input_userauth_info_response(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       KbdintAuthctxt *kbdintctxt;
+       int i, authenticated = 0, res, len;
+       u_int nresp;
+       char **response = NULL, *method;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_info_response: no authctxt");
+       kbdintctxt = authctxt->kbdintctxt;
+       if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
+               fatal("input_userauth_info_response: no kbdintctxt");
+       if (kbdintctxt->device == NULL)
+               fatal("input_userauth_info_response: no device");
+
+       authctxt->postponed = 0;        /* reset */
+       nresp = packet_get_int();
+       if (nresp > 0) {
+               response = xmalloc(nresp * sizeof(char*));
+               for (i = 0; i < nresp; i++)
+                       response[i] = packet_get_string(NULL);
+       }
+       packet_done();
+
+       if (authctxt->valid) {
+               res = kbdintctxt->device->respond(kbdintctxt->ctxt,
+                   nresp, response);
+       } else {
+               res = -1;
+       }
+
+       for (i = 0; i < nresp; i++) {
+               memset(response[i], 'r', strlen(response[i]));
+               xfree(response[i]);
+       }
+       if (response)
+               xfree(response);
+
+       switch (res) {
+       case 0:
+               /* Success! */
+               authenticated = 1;
+               break;
+       case 1:
+               /* Authentication needs further interaction */
+               authctxt->postponed = 1;
+               if (send_userauth_info_request(authctxt) == 0) {
+                       authctxt->postponed = 0;
+               }
+               break;
+       default:
+               /* Failure! */
+               break;
+       }
+
+       len = strlen("keyboard-interactive") + 2 +
+               strlen(kbdintctxt->device->name);
+       method = xmalloc(len);
+       method[0] = '\0';
+       strlcat(method, "keyboard-interactive", len);
+       strlcat(method, "/", len);
+       strlcat(method, kbdintctxt->device->name, len);
+
+       if (!authctxt->postponed) {
+               /* unregister callback */
+               dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+
+               if (authenticated) {
+                       kbdint_free(kbdintctxt);
+                       authctxt->kbdintctxt = NULL;
+               } else {
+                       /* start next device */
+                       /* may set authctxt->postponed */
+                       auth2_challenge_start(authctxt);
+               }
+       }
+       userauth_finish(authctxt, authenticated, method);
+       xfree(method);
+}
diff --git a/openssh/auth2-pam.c b/openssh/auth2-pam.c
new file mode 100644 (file)
index 0000000..b6eaf08
--- /dev/null
@@ -0,0 +1,158 @@
+#include "includes.h"
+RCSID("$Id$");
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+
+#include "ssh.h"
+#include "ssh2.h"
+#include "auth.h"
+#include "auth-pam.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "dispatch.h"
+#include "log.h"
+
+static int do_pam_conversation_kbd_int(int num_msg, 
+    const struct pam_message **msg, struct pam_response **resp, 
+    void *appdata_ptr);
+void input_userauth_info_response_pam(int type, int plen, void *ctxt);
+
+struct {
+       int finished, num_received, num_expected;
+       int *prompts;
+       struct pam_response *responses;
+} context_pam2 = {0, 0, 0, NULL};
+
+static struct pam_conv conv2 = {
+       do_pam_conversation_kbd_int,
+       NULL,
+};
+
+int
+auth2_pam(Authctxt *authctxt)
+{
+       int retval = -1;
+
+       if (authctxt->user == NULL)
+               fatal("auth2_pam: internal error: no user");
+
+       conv2.appdata_ptr = authctxt;
+       do_pam_set_conv(&conv2);
+
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
+           &input_userauth_info_response_pam);
+       retval = (do_pam_authenticate(0) == PAM_SUCCESS);
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+
+       return retval;
+}
+
+static int
+do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
+    struct pam_response **resp, void *appdata_ptr)
+{
+       int i, j, done;
+       char *text;
+
+       context_pam2.finished = 0;
+       context_pam2.num_received = 0;
+       context_pam2.num_expected = 0;
+       context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
+       context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
+       memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
+
+       text = NULL;
+       for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
+               int style = PAM_MSG_MEMBER(msg, i, msg_style);
+               switch (style) {
+               case PAM_PROMPT_ECHO_ON:
+               case PAM_PROMPT_ECHO_OFF:
+                       context_pam2.num_expected++;
+                       break;
+               case PAM_TEXT_INFO:
+               case PAM_ERROR_MSG:
+               default:
+                       /* Capture all these messages to be sent at once */
+                       message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
+                       break;
+               }
+       }
+
+       if (context_pam2.num_expected == 0)
+               return PAM_SUCCESS;
+
+       packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
+       packet_put_cstring(""); /* Name */
+       packet_put_cstring(""); /* Instructions */
+       packet_put_cstring(""); /* Language */
+       packet_put_int(context_pam2.num_expected);
+       
+       for (i = 0, j = 0; i < num_msg; i++) {
+               int style = PAM_MSG_MEMBER(msg, i, msg_style);
+               
+               /* Skip messages which don't need a reply */
+               if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
+                       continue;
+               
+               context_pam2.prompts[j++] = i;
+               if (text) {
+                       message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
+                       packet_put_cstring(text);
+                       text = NULL;
+               } else
+                       packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
+               packet_put_char(style == PAM_PROMPT_ECHO_ON);
+       }
+       packet_send();
+       packet_write_wait();
+
+       /*
+        * Grabbing control of execution and spinning until we get what
+        * we want is probably rude, but it seems to work properly, and
+        * the client *should* be in lock-step with us, so the loop should
+        * only be traversed once.
+        */
+       while(context_pam2.finished == 0) {
+               done = 1;
+               dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
+               if(context_pam2.finished == 0)
+                       debug("extra packet during conversation");
+       }
+
+       if(context_pam2.num_received == context_pam2.num_expected) {
+               *resp = context_pam2.responses;
+               return PAM_SUCCESS;
+       } else
+               return PAM_CONV_ERR;
+}
+
+void
+input_userauth_info_response_pam(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       unsigned int nresp = 0, rlen = 0, i = 0;
+       char *resp;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_info_response_pam: no authentication context");
+
+       nresp = packet_get_int();       /* Number of responses. */
+       debug("got %d responses", nresp);
+
+       for (i = 0; i < nresp; i++) {
+               int j = context_pam2.prompts[i];
+
+               resp = packet_get_string(&rlen);
+               context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
+               context_pam2.responses[j].resp = xstrdup(resp);
+               xfree(resp);
+               context_pam2.num_received++;
+       }
+
+       context_pam2.finished = 1;
+
+       packet_done();
+}
+
+#endif
diff --git a/openssh/auth2-pam.h b/openssh/auth2-pam.h
new file mode 100644 (file)
index 0000000..7992803
--- /dev/null
@@ -0,0 +1,8 @@
+/* $Id$ */
+
+#include "includes.h"
+#ifdef USE_PAM
+
+int    auth2_pam(Authctxt *authctxt);
+
+#endif /* USE_PAM */
diff --git a/openssh/auth2.c b/openssh/auth2.c
new file mode 100644 (file)
index 0000000..1920eb3
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth2.c,v 1.72 2001/11/07 22:41:51 markus Exp $");
+
+#include <openssl/evp.h>
+
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "sshpty.h"
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "compat.h"
+#include "channels.h"
+#include "bufaux.h"
+#include "auth.h"
+#include "session.h"
+#include "dispatch.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "pathnames.h"
+#include "uidswap.h"
+#include "auth-options.h"
+#include "misc.h"
+#include "hostfile.h"
+#include "canohost.h"
+#include "match.h"
+
+/* import */
+extern ServerOptions options;
+extern u_char *session_id2;
+extern int session_id2_len;
+
+static Authctxt        *x_authctxt = NULL;
+static int one = 1;
+
+typedef struct Authmethod Authmethod;
+struct Authmethod {
+       char    *name;
+       int     (*userauth)(Authctxt *authctxt);
+       int     *enabled;
+};
+
+/* protocol */
+
+static void input_service_request(int, int, void *);
+static void input_userauth_request(int, int, void *);
+static void protocol_error(int, int, void *);
+
+/* helper */
+static Authmethod *authmethod_lookup(const char *);
+static char *authmethods_get(void);
+static int user_key_allowed(struct passwd *, Key *);
+static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
+
+/* auth */
+static void userauth_banner(void);
+static int userauth_none(Authctxt *);
+static int userauth_passwd(Authctxt *);
+static int userauth_pubkey(Authctxt *);
+static int userauth_hostbased(Authctxt *);
+static int userauth_kbdint(Authctxt *);
+
+Authmethod authmethods[] = {
+       {"none",
+               userauth_none,
+               &one},
+       {"publickey",
+               userauth_pubkey,
+               &options.pubkey_authentication},
+       {"password",
+               userauth_passwd,
+               &options.password_authentication},
+       {"keyboard-interactive",
+               userauth_kbdint,
+               &options.kbd_interactive_authentication},
+       {"hostbased",
+               userauth_hostbased,
+               &options.hostbased_authentication},
+       {NULL, NULL, NULL}
+};
+
+/*
+ * loop until authctxt->success == TRUE
+ */
+
+void
+do_authentication2()
+{
+       Authctxt *authctxt = authctxt_new();
+
+       x_authctxt = authctxt;          /*XXX*/
+
+       /* challenge-response is implemented via keyboard interactive */
+       if (options.challenge_response_authentication)
+               options.kbd_interactive_authentication = 1;
+       if (options.pam_authentication_via_kbd_int)
+               options.kbd_interactive_authentication = 1;
+
+       dispatch_init(&protocol_error);
+       dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
+       dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
+       do_authenticated(authctxt);
+}
+
+static void
+protocol_error(int type, int plen, void *ctxt)
+{
+       log("auth: protocol error: type %d plen %d", type, plen);
+       packet_start(SSH2_MSG_UNIMPLEMENTED);
+       packet_put_int(0);
+       packet_send();
+       packet_write_wait();
+}
+
+static void
+input_service_request(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       u_int len;
+       int accept = 0;
+       char *service = packet_get_string(&len);
+       packet_done();
+
+       if (authctxt == NULL)
+               fatal("input_service_request: no authctxt");
+
+       if (strcmp(service, "ssh-userauth") == 0) {
+               if (!authctxt->success) {
+                       accept = 1;
+                       /* now we can handle user-auth requests */
+                       dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
+               }
+       }
+       /* XXX all other service requests are denied */
+
+       if (accept) {
+               packet_start(SSH2_MSG_SERVICE_ACCEPT);
+               packet_put_cstring(service);
+               packet_send();
+               packet_write_wait();
+       } else {
+               debug("bad service request %s", service);
+               packet_disconnect("bad service request %s", service);
+       }
+       xfree(service);
+}
+
+static void
+input_userauth_request(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Authmethod *m = NULL;
+       char *user, *service, *method, *style = NULL;
+       int authenticated = 0;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_request: no authctxt");
+
+       user = packet_get_string(NULL);
+       service = packet_get_string(NULL);
+       method = packet_get_string(NULL);
+       debug("userauth-request for user %s service %s method %s", user, service, method);
+       debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+
+       if ((style = strchr(user, ':')) != NULL)
+               *style++ = 0;
+
+       if (authctxt->attempt++ == 0) {
+               /* setup auth context */
+               struct passwd *pw = NULL;
+               pw = getpwnam(user);
+               if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
+                       authctxt->pw = pwcopy(pw);
+                       authctxt->valid = 1;
+                       debug2("input_userauth_request: setting up authctxt for %s", user);
+#ifdef USE_PAM
+                       start_pam(pw->pw_name);
+#endif
+               } else {
+                       log("input_userauth_request: illegal user %s", user);
+#ifdef USE_PAM
+                       start_pam("NOUSER");
+#endif
+               }
+               setproctitle("%s", pw ? user : "unknown");
+               authctxt->user = xstrdup(user);
+               authctxt->service = xstrdup(service);
+               authctxt->style = style ? xstrdup(style) : NULL;
+       } else if (strcmp(user, authctxt->user) != 0 ||
+           strcmp(service, authctxt->service) != 0) {
+               packet_disconnect("Change of username or service not allowed: "
+                   "(%s,%s) -> (%s,%s)",
+                   authctxt->user, authctxt->service, user, service);
+       }
+       /* reset state */
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
+       authctxt->postponed = 0;
+#ifdef BSD_AUTH
+       if (authctxt->as) {
+               auth_close(authctxt->as);
+               authctxt->as = NULL;
+       }
+#endif
+
+       /* try to authenticate user */
+       m = authmethod_lookup(method);
+       if (m != NULL) {
+               debug2("input_userauth_request: try method %s", method);
+               authenticated = m->userauth(authctxt);
+       }
+       userauth_finish(authctxt, authenticated, method);
+
+       xfree(service);
+       xfree(user);
+       xfree(method);
+}
+
+void
+userauth_finish(Authctxt *authctxt, int authenticated, char *method)
+{
+       char *methods;
+
+       if (!authctxt->valid && authenticated)
+               fatal("INTERNAL ERROR: authenticated invalid user %s",
+                   authctxt->user);
+
+       /* Special handling for root */
+       if (authenticated && authctxt->pw->pw_uid == 0 &&
+           !auth_root_allowed(method))
+               authenticated = 0;
+
+#ifdef USE_PAM
+       if (authenticated && authctxt->user && !do_pam_account(authctxt->user,
+           NULL))
+               authenticated = 0;
+#endif /* USE_PAM */
+
+       /* Log before sending the reply */
+       auth_log(authctxt, authenticated, method, " ssh2");
+
+       if (authctxt->postponed)
+               return;
+
+       /* XXX todo: check if multiple auth methods are needed */
+       if (authenticated == 1) {
+               /* turn off userauth */
+               dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
+               packet_start(SSH2_MSG_USERAUTH_SUCCESS);
+               packet_send();
+               packet_write_wait();
+               /* now we can break out */
+               authctxt->success = 1;
+       } else {
+               if (authctxt->failures++ > AUTH_FAIL_MAX) {
+#ifdef WITH_AIXAUTHENTICATE
+                       loginfailed(authctxt->user,
+                           get_canonical_hostname(options.reverse_mapping_check),
+                           "ssh");
+#endif /* WITH_AIXAUTHENTICATE */
+                       packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+               }
+               methods = authmethods_get();
+               packet_start(SSH2_MSG_USERAUTH_FAILURE);
+               packet_put_cstring(methods);
+               packet_put_char(0);     /* XXX partial success, unused */
+               packet_send();
+               packet_write_wait();
+               xfree(methods);
+       }
+}
+
+static void
+userauth_banner(void)
+{
+       struct stat st;
+       char *banner = NULL;
+       off_t len, n;
+       int fd;
+
+       if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
+               return;
+       if ((fd = open(options.banner, O_RDONLY)) < 0)
+               return;
+       if (fstat(fd, &st) < 0)
+               goto done;
+       len = st.st_size;
+       banner = xmalloc(len + 1);
+       if ((n = read(fd, banner, len)) < 0)
+               goto done;
+       banner[n] = '\0';
+       packet_start(SSH2_MSG_USERAUTH_BANNER);
+       packet_put_cstring(banner);
+       packet_put_cstring("");         /* language, unused */
+       packet_send();
+       debug("userauth_banner: sent");
+done:
+       if (banner)
+               xfree(banner);
+       close(fd);
+       return;
+}
+
+static int
+userauth_none(Authctxt *authctxt)
+{
+       /* disable method "none", only allowed one time */
+       Authmethod *m = authmethod_lookup("none");
+       if (m != NULL)
+               m->enabled = NULL;
+       packet_done();
+       userauth_banner();
+
+       if (authctxt->valid == 0)
+               return(0);
+
+#ifdef HAVE_CYGWIN
+       if (check_nt_auth(1, authctxt->pw->pw_uid) == 0)
+               return(0);
+#endif
+#ifdef USE_PAM
+       return auth_pam_password(authctxt->pw, "");
+#elif defined(HAVE_OSF_SIA)
+       return 0;
+#else /* !HAVE_OSF_SIA && !USE_PAM */
+       return auth_password(authctxt, "");
+#endif /* USE_PAM */
+}
+
+static int
+userauth_passwd(Authctxt *authctxt)
+{
+       char *password;
+       int authenticated = 0;
+       int change;
+       u_int len;
+       change = packet_get_char();
+       if (change)
+               log("password change not supported");
+       password = packet_get_string(&len);
+       packet_done();
+       if (authctxt->valid &&
+#ifdef HAVE_CYGWIN
+               check_nt_auth(1, authctxt->pw->pw_uid) &&
+#endif
+#ifdef USE_PAM
+           auth_pam_password(authctxt->pw, password) == 1)
+#elif defined(HAVE_OSF_SIA)
+           auth_sia_password(authctxt->user, password) == 1)
+#else /* !USE_PAM && !HAVE_OSF_SIA */
+           auth_password(authctxt, password) == 1)
+#endif /* USE_PAM */
+               authenticated = 1;
+       memset(password, 0, len);
+       xfree(password);
+       return authenticated;
+}
+
+static int
+userauth_kbdint(Authctxt *authctxt)
+{
+       int authenticated = 0;
+       char *lang, *devs;
+
+       lang = packet_get_string(NULL);
+       devs = packet_get_string(NULL);
+       packet_done();
+
+       debug("keyboard-interactive devs %s", devs);
+
+       if (options.challenge_response_authentication)
+               authenticated = auth2_challenge(authctxt, devs);
+
+#ifdef USE_PAM
+       if (authenticated == 0 && options.pam_authentication_via_kbd_int)
+               authenticated = auth2_pam(authctxt);
+#endif
+       xfree(devs);
+       xfree(lang);
+#ifdef HAVE_CYGWIN
+       if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
+               return(0);
+#endif
+       return authenticated;
+}
+
+static int
+userauth_pubkey(Authctxt *authctxt)
+{
+       Buffer b;
+       Key *key;
+       char *pkalg, *pkblob, *sig;
+       u_int alen, blen, slen;
+       int have_sig, pktype;
+       int authenticated = 0;
+
+       if (!authctxt->valid) {
+               debug2("userauth_pubkey: disabled because of invalid user");
+               return 0;
+       }
+       have_sig = packet_get_char();
+       if (datafellows & SSH_BUG_PKAUTH) {
+               debug2("userauth_pubkey: SSH_BUG_PKAUTH");
+               /* no explicit pkalg given */
+               pkblob = packet_get_string(&blen);
+               buffer_init(&b);
+               buffer_append(&b, pkblob, blen);
+               /* so we have to extract the pkalg from the pkblob */
+               pkalg = buffer_get_string(&b, &alen);
+               buffer_free(&b);
+       } else {
+               pkalg = packet_get_string(&alen);
+               pkblob = packet_get_string(&blen);
+       }
+       pktype = key_type_from_name(pkalg);
+       if (pktype == KEY_UNSPEC) {
+               /* this is perfectly legal */
+               log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
+               xfree(pkalg);
+               xfree(pkblob);
+               return 0;
+       }
+       key = key_from_blob(pkblob, blen);
+       if (key != NULL) {
+               if (have_sig) {
+                       sig = packet_get_string(&slen);
+                       packet_done();
+                       buffer_init(&b);
+                       if (datafellows & SSH_OLD_SESSIONID) {
+                               buffer_append(&b, session_id2, session_id2_len);
+                       } else {
+                               buffer_put_string(&b, session_id2, session_id2_len);
+                       }
+                       /* reconstruct packet */
+                       buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+                       buffer_put_cstring(&b, authctxt->user);
+                       buffer_put_cstring(&b,
+                           datafellows & SSH_BUG_PKSERVICE ?
+                           "ssh-userauth" :
+                           authctxt->service);
+                       if (datafellows & SSH_BUG_PKAUTH) {
+                               buffer_put_char(&b, have_sig);
+                       } else {
+                               buffer_put_cstring(&b, "publickey");
+                               buffer_put_char(&b, have_sig);
+                               buffer_put_cstring(&b, pkalg);
+                       }
+                       buffer_put_string(&b, pkblob, blen);
+#ifdef DEBUG_PK
+                       buffer_dump(&b);
+#endif
+                       /* test for correct signature */
+                       if (user_key_allowed(authctxt->pw, key) &&
+                           key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+                               authenticated = 1;
+                       buffer_clear(&b);
+                       xfree(sig);
+               } else {
+                       debug("test whether pkalg/pkblob are acceptable");
+                       packet_done();
+
+                       /* XXX fake reply and always send PK_OK ? */
+                       /*
+                        * XXX this allows testing whether a user is allowed
+                        * to login: if you happen to have a valid pubkey this
+                        * message is sent. the message is NEVER sent at all
+                        * if a user is not allowed to login. is this an
+                        * issue? -markus
+                        */
+                       if (user_key_allowed(authctxt->pw, key)) {
+                               packet_start(SSH2_MSG_USERAUTH_PK_OK);
+                               packet_put_string(pkalg, alen);
+                               packet_put_string(pkblob, blen);
+                               packet_send();
+                               packet_write_wait();
+                               authctxt->postponed = 1;
+                       }
+               }
+               if (authenticated != 1)
+                       auth_clear_options();
+               key_free(key);
+       }
+       debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
+       xfree(pkalg);
+       xfree(pkblob);
+#ifdef HAVE_CYGWIN
+       if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
+               return(0);
+#endif
+       return authenticated;
+}
+
+static int
+userauth_hostbased(Authctxt *authctxt)
+{
+       Buffer b;
+       Key *key;
+       char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
+       u_int alen, blen, slen;
+       int pktype;
+       int authenticated = 0;
+
+       if (!authctxt->valid) {
+               debug2("userauth_hostbased: disabled because of invalid user");
+               return 0;
+       }
+       pkalg = packet_get_string(&alen);
+       pkblob = packet_get_string(&blen);
+       chost = packet_get_string(NULL);
+       cuser = packet_get_string(NULL);
+       sig = packet_get_string(&slen);
+
+       debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
+           cuser, chost, pkalg, slen);
+#ifdef DEBUG_PK
+       debug("signature:");
+       buffer_init(&b);
+       buffer_append(&b, sig, slen);
+       buffer_dump(&b);
+       buffer_free(&b);
+#endif
+       pktype = key_type_from_name(pkalg);
+       if (pktype == KEY_UNSPEC) {
+               /* this is perfectly legal */
+               log("userauth_hostbased: unsupported "
+                   "public key algorithm: %s", pkalg);
+               goto done;
+       }
+       key = key_from_blob(pkblob, blen);
+       if (key == NULL) {
+               debug("userauth_hostbased: cannot decode key: %s", pkalg);
+               goto done;
+       }
+       service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
+           authctxt->service;
+       buffer_init(&b);
+       buffer_put_string(&b, session_id2, session_id2_len);
+       /* reconstruct packet */
+       buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+       buffer_put_cstring(&b, authctxt->user);
+       buffer_put_cstring(&b, service);
+       buffer_put_cstring(&b, "hostbased");
+       buffer_put_string(&b, pkalg, alen);
+       buffer_put_string(&b, pkblob, blen);
+       buffer_put_cstring(&b, chost);
+       buffer_put_cstring(&b, cuser);
+#ifdef DEBUG_PK
+       buffer_dump(&b);
+#endif
+       /* test for allowed key and correct signature */
+       if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
+           key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+               authenticated = 1;
+
+       buffer_clear(&b);
+       key_free(key);
+
+done:
+       debug2("userauth_hostbased: authenticated %d", authenticated);
+       xfree(pkalg);
+       xfree(pkblob);
+       xfree(cuser);
+       xfree(chost);
+       xfree(sig);
+       return authenticated;
+}
+
+/* get current user */
+
+struct passwd*
+auth_get_user(void)
+{
+       return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
+}
+
+#define        DELIM   ","
+
+static char *
+authmethods_get(void)
+{
+       Authmethod *method = NULL;
+       u_int size = 0;
+       char *list;
+
+       for (method = authmethods; method->name != NULL; method++) {
+               if (strcmp(method->name, "none") == 0)
+                       continue;
+               if (method->enabled != NULL && *(method->enabled) != 0) {
+                       if (size != 0)
+                               size += strlen(DELIM);
+                       size += strlen(method->name);
+               }
+       }
+       size++;                 /* trailing '\0' */
+       list = xmalloc(size);
+       list[0] = '\0';
+
+       for (method = authmethods; method->name != NULL; method++) {
+               if (strcmp(method->name, "none") == 0)
+                       continue;
+               if (method->enabled != NULL && *(method->enabled) != 0) {
+                       if (list[0] != '\0')
+                               strlcat(list, DELIM, size);
+                       strlcat(list, method->name, size);
+               }
+       }
+       return list;
+}
+
+static Authmethod *
+authmethod_lookup(const char *name)
+{
+       Authmethod *method = NULL;
+       if (name != NULL)
+               for (method = authmethods; method->name != NULL; method++)
+                       if (method->enabled != NULL &&
+                           *(method->enabled) != 0 &&
+                           strcmp(name, method->name) == 0)
+                               return method;
+       debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
+       return NULL;
+}
+
+/* return 1 if user allows given key */
+static int
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
+{
+       char line[8192];
+       int found_key = 0;
+       FILE *f;
+       u_long linenum = 0;
+       struct stat st;
+       Key *found;
+
+       if (pw == NULL)
+               return 0;
+
+       /* Temporarily use the user's uid. */
+       temporarily_use_uid(pw);
+
+       debug("trying public key file %s", file);
+
+       /* Fail quietly if file does not exist */
+       if (stat(file, &st) < 0) {
+               /* Restore the privileged uid. */
+               restore_uid();
+               return 0;
+       }
+       /* Open the file containing the authorized keys. */
+       f = fopen(file, "r");
+       if (!f) {
+               /* Restore the privileged uid. */
+               restore_uid();
+               return 0;
+       }
+       if (options.strict_modes &&
+           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+               fclose(f);
+               log("Authentication refused: %s", line);
+               restore_uid();
+               return 0;
+       }
+
+       found_key = 0;
+       found = key_new(key->type);
+
+       while (fgets(line, sizeof(line), f)) {
+               char *cp, *options = NULL;
+               linenum++;
+               /* Skip leading whitespace, empty and comment lines. */
+               for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '\n' || *cp == '#')
+                       continue;
+
+               if (key_read(found, &cp) != 1) {
+                       /* no key?  check if there are options for this key */
+                       int quoted = 0;
+                       debug2("user_key_allowed: check options: '%s'", cp);
+                       options = cp;
+                       for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+                               if (*cp == '\\' && cp[1] == '"')
+                                       cp++;   /* Skip both */
+                               else if (*cp == '"')
+                                       quoted = !quoted;
+                       }
+                       /* Skip remaining whitespace. */
+                       for (; *cp == ' ' || *cp == '\t'; cp++)
+                               ;
+                       if (key_read(found, &cp) != 1) {
+                               debug2("user_key_allowed: advance: '%s'", cp);
+                               /* still no key?  advance to next line*/
+                               continue;
+                       }
+               }
+               if (key_equal(found, key) &&
+                   auth_parse_options(pw, options, file, linenum) == 1) {
+                       found_key = 1;
+                       debug("matching key found: file %s, line %lu",
+                           file, linenum);
+                       break;
+               }
+       }
+       restore_uid();
+       fclose(f);
+       key_free(found);
+       if (!found_key)
+               debug2("key not found");
+       return found_key;
+}
+
+/* check whether given key is in .ssh/authorized_keys* */
+static int
+user_key_allowed(struct passwd *pw, Key *key)
+{
+       int success;
+       char *file;
+
+       file = authorized_keys_file(pw);
+       success = user_key_allowed2(pw, key, file);
+       xfree(file);
+       if (success)
+               return success;
+
+       /* try suffix "2" for backward compat, too */
+       file = authorized_keys_file2(pw);
+       success = user_key_allowed2(pw, key, file);
+       xfree(file);
+       return success;
+}
+
+/* return 1 if given hostkey is allowed */
+static int
+hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
+    Key *key)
+{
+       const char *resolvedname, *ipaddr, *lookup;
+       int host_status, len;
+
+       resolvedname = get_canonical_hostname(options.reverse_mapping_check);
+       ipaddr = get_remote_ipaddr();
+
+       debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
+           chost, resolvedname, ipaddr);
+
+       if (options.hostbased_uses_name_from_packet_only) {
+               if (auth_rhosts2(pw, cuser, chost, chost) == 0)
+                       return 0;
+               lookup = chost;
+       } else {
+               if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
+                       debug2("stripping trailing dot from chost %s", chost);
+                       chost[len - 1] = '\0';
+               }
+               if (strcasecmp(resolvedname, chost) != 0)
+                       log("userauth_hostbased mismatch: "
+                           "client sends %s, but we resolve %s to %s",
+                           chost, ipaddr, resolvedname);
+               if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
+                       return 0;
+               lookup = resolvedname;
+       }
+       debug2("userauth_hostbased: access allowed by auth_rhosts2");
+
+       host_status = check_key_in_hostfiles(pw, key, lookup,
+           _PATH_SSH_SYSTEM_HOSTFILE,
+           options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
+
+       /* backward compat if no key has been found. */
+       if (host_status == HOST_NEW)
+               host_status = check_key_in_hostfiles(pw, key, lookup,
+                   _PATH_SSH_SYSTEM_HOSTFILE2,
+                   options.ignore_user_known_hosts ? NULL :
+                   _PATH_SSH_USER_HOSTFILE2);
+
+       return (host_status == HOST_OK);
+}
+
diff --git a/openssh/authfd.c b/openssh/authfd.c
new file mode 100644 (file)
index 0000000..d6366ee
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for connecting the local authentication agent.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * SSH2 implementation,
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: authfd.c,v 1.45 2001/09/19 19:35:30 stevesk Exp $");
+
+#include <openssl/evp.h>
+
+#include "ssh.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "xmalloc.h"
+#include "getput.h"
+#include "key.h"
+#include "authfd.h"
+#include "cipher.h"
+#include "kex.h"
+#include "compat.h"
+#include "log.h"
+#include "atomicio.h"
+
+/* helper */
+int    decode_reply(int type);
+
+/* macro to check for "agent failure" message */
+#define agent_failed(x) \
+    ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \
+     (x == SSH2_AGENT_FAILURE))
+
+/* Returns the number of the authentication fd, or -1 if there is none. */
+
+int
+ssh_get_authentication_socket(void)
+{
+       const char *authsocket;
+       int sock;
+       struct sockaddr_un sunaddr;
+
+       authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
+       if (!authsocket)
+               return -1;
+
+       sunaddr.sun_family = AF_UNIX;
+       strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
+
+       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0)
+               return -1;
+
+       /* close on exec */
+       if (fcntl(sock, F_SETFD, 1) == -1) {
+               close(sock);
+               return -1;
+       }
+       if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) {
+               close(sock);
+               return -1;
+       }
+       return sock;
+}
+
+static int
+ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
+{
+       int l, len;
+       char buf[1024];
+
+       /* Get the length of the message, and format it in the buffer. */
+       len = buffer_len(request);
+       PUT_32BIT(buf, len);
+
+       /* Send the length and then the packet to the agent. */
+       if (atomicio(write, auth->fd, buf, 4) != 4 ||
+           atomicio(write, auth->fd, buffer_ptr(request),
+           buffer_len(request)) != buffer_len(request)) {
+               error("Error writing to authentication socket.");
+               return 0;
+       }
+       /*
+        * Wait for response from the agent.  First read the length of the
+        * response packet.
+        */
+       len = 4;
+       while (len > 0) {
+               l = read(auth->fd, buf + 4 - len, len);
+               if (l == -1 && (errno == EAGAIN || errno == EINTR))
+                       continue;
+               if (l <= 0) {
+                       error("Error reading response length from authentication socket.");
+                       return 0;
+               }
+               len -= l;
+       }
+
+       /* Extract the length, and check it for sanity. */
+       len = GET_32BIT(buf);
+       if (len > 256 * 1024)
+               fatal("Authentication response too long: %d", len);
+
+       /* Read the rest of the response in to the buffer. */
+       buffer_clear(reply);
+       while (len > 0) {
+               l = len;
+               if (l > sizeof(buf))
+                       l = sizeof(buf);
+               l = read(auth->fd, buf, l);
+               if (l == -1 && (errno == EAGAIN || errno == EINTR))
+                       continue;
+               if (l <= 0) {
+                       error("Error reading response from authentication socket.");
+                       return 0;
+               }
+               buffer_append(reply, (char *) buf, l);
+               len -= l;
+       }
+       return 1;
+}
+
+/*
+ * Closes the agent socket if it should be closed (depends on how it was
+ * obtained).  The argument must have been returned by
+ * ssh_get_authentication_socket().
+ */
+
+void
+ssh_close_authentication_socket(int sock)
+{
+       if (getenv(SSH_AUTHSOCKET_ENV_NAME))
+               close(sock);
+}
+
+/*
+ * Opens and connects a private socket for communication with the
+ * authentication agent.  Returns the file descriptor (which must be
+ * shut down and closed by the caller when no longer needed).
+ * Returns NULL if an error occurred and the connection could not be
+ * opened.
+ */
+
+AuthenticationConnection *
+ssh_get_authentication_connection(void)
+{
+       AuthenticationConnection *auth;
+       int sock;
+
+       sock = ssh_get_authentication_socket();
+
+       /*
+        * Fail if we couldn't obtain a connection.  This happens if we
+        * exited due to a timeout.
+        */
+       if (sock < 0)
+               return NULL;
+
+       auth = xmalloc(sizeof(*auth));
+       auth->fd = sock;
+       buffer_init(&auth->identities);
+       auth->howmany = 0;
+
+       return auth;
+}
+
+/*
+ * Closes the connection to the authentication agent and frees any associated
+ * memory.
+ */
+
+void
+ssh_close_authentication_connection(AuthenticationConnection *auth)
+{
+       buffer_free(&auth->identities);
+       close(auth->fd);
+       xfree(auth);
+}
+
+/*
+ * Returns the first authentication identity held by the agent.
+ */
+
+int
+ssh_get_num_identities(AuthenticationConnection *auth, int version)
+{
+       int type, code1 = 0, code2 = 0;
+       Buffer request;
+
+       switch(version){
+       case 1:
+               code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
+               code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
+               break;
+       case 2:
+               code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
+               code2 = SSH2_AGENT_IDENTITIES_ANSWER;
+               break;
+       default:
+               return 0;
+       }
+
+       /*
+        * Send a message to the agent requesting for a list of the
+        * identities it can represent.
+        */
+       buffer_init(&request);
+       buffer_put_char(&request, code1);
+
+       buffer_clear(&auth->identities);
+       if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
+               buffer_free(&request);
+               return 0;
+       }
+       buffer_free(&request);
+
+       /* Get message type, and verify that we got a proper answer. */
+       type = buffer_get_char(&auth->identities);
+       if (agent_failed(type)) {
+               return 0;
+       } else if (type != code2) {
+               fatal("Bad authentication reply message type: %d", type);
+       }
+
+       /* Get the number of entries in the response and check it for sanity. */
+       auth->howmany = buffer_get_int(&auth->identities);
+       if (auth->howmany > 1024)
+               fatal("Too many identities in authentication reply: %d",
+                   auth->howmany);
+
+       return auth->howmany;
+}
+
+Key *
+ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
+{
+       /* get number of identities and return the first entry (if any). */
+       if (ssh_get_num_identities(auth, version) > 0)
+               return ssh_get_next_identity(auth, comment, version);
+       return NULL;
+}
+
+Key *
+ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
+{
+       u_int bits;
+       u_char *blob;
+       u_int blen;
+       Key *key = NULL;
+
+       /* Return failure if no more entries. */
+       if (auth->howmany <= 0)
+               return NULL;
+
+       /*
+        * Get the next entry from the packet.  These will abort with a fatal
+        * error if the packet is too short or contains corrupt data.
+        */
+       switch(version){
+       case 1:
+               key = key_new(KEY_RSA1);
+               bits = buffer_get_int(&auth->identities);
+               buffer_get_bignum(&auth->identities, key->rsa->e);
+               buffer_get_bignum(&auth->identities, key->rsa->n);
+               *comment = buffer_get_string(&auth->identities, NULL);
+               if (bits != BN_num_bits(key->rsa->n))
+                       log("Warning: identity keysize mismatch: actual %d, announced %u",
+                           BN_num_bits(key->rsa->n), bits);
+               break;
+       case 2:
+               blob = buffer_get_string(&auth->identities, &blen);
+               *comment = buffer_get_string(&auth->identities, NULL);
+               key = key_from_blob(blob, blen);
+               xfree(blob);
+               break;
+       default:
+               return NULL;
+               break;
+       }
+       /* Decrement the number of remaining entries. */
+       auth->howmany--;
+       return key;
+}
+
+/*
+ * Generates a random challenge, sends it to the agent, and waits for
+ * response from the agent.  Returns true (non-zero) if the agent gave the
+ * correct answer, zero otherwise.  Response type selects the style of
+ * response desired, with 0 corresponding to protocol version 1.0 (no longer
+ * supported) and 1 corresponding to protocol version 1.1.
+ */
+
+int
+ssh_decrypt_challenge(AuthenticationConnection *auth,
+    Key* key, BIGNUM *challenge,
+    u_char session_id[16],
+    u_int response_type,
+    u_char response[16])
+{
+       Buffer buffer;
+       int success = 0;
+       int i;
+       int type;
+
+       if (key->type != KEY_RSA1)
+               return 0;
+       if (response_type == 0) {
+               log("Compatibility with ssh protocol version 1.0 no longer supported.");
+               return 0;
+       }
+       buffer_init(&buffer);
+       buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
+       buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
+       buffer_put_bignum(&buffer, key->rsa->e);
+       buffer_put_bignum(&buffer, key->rsa->n);
+       buffer_put_bignum(&buffer, challenge);
+       buffer_append(&buffer, (char *) session_id, 16);
+       buffer_put_int(&buffer, response_type);
+
+       if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
+               buffer_free(&buffer);
+               return 0;
+       }
+       type = buffer_get_char(&buffer);
+
+       if (agent_failed(type)) {
+               log("Agent admitted failure to authenticate using the key.");
+       } else if (type != SSH_AGENT_RSA_RESPONSE) {
+               fatal("Bad authentication response: %d", type);
+       } else {
+               success = 1;
+               /*
+                * Get the response from the packet.  This will abort with a
+                * fatal error if the packet is corrupt.
+                */
+               for (i = 0; i < 16; i++)
+                       response[i] = buffer_get_char(&buffer);
+       }
+       buffer_free(&buffer);
+       return success;
+}
+
+/* ask agent to sign data, returns -1 on error, 0 on success */
+int
+ssh_agent_sign(AuthenticationConnection *auth,
+    Key *key,
+    u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       extern int datafellows;
+       Buffer msg;
+       u_char *blob;
+       u_int blen;
+       int type, flags = 0;
+       int ret = -1;
+
+       if (key_to_blob(key, &blob, &blen) == 0)
+               return -1;
+
+       if (datafellows & SSH_BUG_SIGBLOB)
+               flags = SSH_AGENT_OLD_SIGNATURE;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
+       buffer_put_string(&msg, blob, blen);
+       buffer_put_string(&msg, data, datalen);
+       buffer_put_int(&msg, flags);
+       xfree(blob);
+
+       if (ssh_request_reply(auth, &msg, &msg) == 0) {
+               buffer_free(&msg);
+               return -1;
+       }
+       type = buffer_get_char(&msg);
+       if (agent_failed(type)) {
+               log("Agent admitted failure to sign using the key.");
+       } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
+               fatal("Bad authentication response: %d", type);
+       } else {
+               ret = 0;
+               *sigp = buffer_get_string(&msg, lenp);
+       }
+       buffer_free(&msg);
+       return ret;
+}
+
+/* Encode key for a message to the agent. */
+
+static void
+ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
+{
+       buffer_clear(b);
+       buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
+       buffer_put_int(b, BN_num_bits(key->n));
+       buffer_put_bignum(b, key->n);
+       buffer_put_bignum(b, key->e);
+       buffer_put_bignum(b, key->d);
+       /* To keep within the protocol: p < q for ssh. in SSL p > q */
+       buffer_put_bignum(b, key->iqmp);        /* ssh key->u */
+       buffer_put_bignum(b, key->q);   /* ssh key->p, SSL key->q */
+       buffer_put_bignum(b, key->p);   /* ssh key->q, SSL key->p */
+       buffer_put_cstring(b, comment);
+}
+
+static void
+ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
+{
+       buffer_clear(b);
+       buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
+       buffer_put_cstring(b, key_ssh_name(key));
+       switch(key->type){
+       case KEY_RSA:
+               buffer_put_bignum2(b, key->rsa->n);
+               buffer_put_bignum2(b, key->rsa->e);
+               buffer_put_bignum2(b, key->rsa->d);
+               buffer_put_bignum2(b, key->rsa->iqmp);
+               buffer_put_bignum2(b, key->rsa->p);
+               buffer_put_bignum2(b, key->rsa->q);
+               break;
+       case KEY_DSA:
+               buffer_put_bignum2(b, key->dsa->p);
+               buffer_put_bignum2(b, key->dsa->q);
+               buffer_put_bignum2(b, key->dsa->g);
+               buffer_put_bignum2(b, key->dsa->pub_key);
+               buffer_put_bignum2(b, key->dsa->priv_key);
+               break;
+       }
+       buffer_put_cstring(b, comment);
+}
+
+/*
+ * Adds an identity to the authentication server.  This call is not meant to
+ * be used by normal applications.
+ */
+
+int
+ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
+{
+       Buffer msg;
+       int type;
+
+       buffer_init(&msg);
+
+       switch (key->type) {
+       case KEY_RSA1:
+               ssh_encode_identity_rsa1(&msg, key->rsa, comment);
+               break;
+       case KEY_RSA:
+       case KEY_DSA:
+               ssh_encode_identity_ssh2(&msg, key, comment);
+               break;
+       default:
+               buffer_free(&msg);
+               return 0;
+               break;
+       }
+       if (ssh_request_reply(auth, &msg, &msg) == 0) {
+               buffer_free(&msg);
+               return 0;
+       }
+       type = buffer_get_char(&msg);
+       buffer_free(&msg);
+       return decode_reply(type);
+}
+
+/*
+ * Removes an identity from the authentication server.  This call is not
+ * meant to be used by normal applications.
+ */
+
+int
+ssh_remove_identity(AuthenticationConnection *auth, Key *key)
+{
+       Buffer msg;
+       int type;
+       u_char *blob;
+       u_int blen;
+
+       buffer_init(&msg);
+
+       if (key->type == KEY_RSA1) {
+               buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
+               buffer_put_int(&msg, BN_num_bits(key->rsa->n));
+               buffer_put_bignum(&msg, key->rsa->e);
+               buffer_put_bignum(&msg, key->rsa->n);
+       } else if (key->type == KEY_DSA || key->type == KEY_RSA) {
+               key_to_blob(key, &blob, &blen);
+               buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
+               buffer_put_string(&msg, blob, blen);
+               xfree(blob);
+       } else {
+               buffer_free(&msg);
+               return 0;
+       }
+       if (ssh_request_reply(auth, &msg, &msg) == 0) {
+               buffer_free(&msg);
+               return 0;
+       }
+       type = buffer_get_char(&msg);
+       buffer_free(&msg);
+       return decode_reply(type);
+}
+
+int
+ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id)
+{
+       Buffer msg;
+       int type;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY :
+           SSH_AGENTC_REMOVE_SMARTCARD_KEY);
+       buffer_put_cstring(&msg, reader_id);
+       if (ssh_request_reply(auth, &msg, &msg) == 0) {
+               buffer_free(&msg);
+               return 0;
+       }
+       type = buffer_get_char(&msg);
+       buffer_free(&msg);
+       return decode_reply(type);
+}
+
+/*
+ * Removes all identities from the agent.  This call is not meant to be used
+ * by normal applications.
+ */
+
+int
+ssh_remove_all_identities(AuthenticationConnection *auth, int version)
+{
+       Buffer msg;
+       int type;
+       int code = (version==1) ?
+               SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
+               SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, code);
+
+       if (ssh_request_reply(auth, &msg, &msg) == 0) {
+               buffer_free(&msg);
+               return 0;
+       }
+       type = buffer_get_char(&msg);
+       buffer_free(&msg);
+       return decode_reply(type);
+}
+
+int
+decode_reply(int type)
+{
+       switch (type) {
+       case SSH_AGENT_FAILURE:
+       case SSH_COM_AGENT2_FAILURE:
+       case SSH2_AGENT_FAILURE:
+               log("SSH_AGENT_FAILURE");
+               return 0;
+       case SSH_AGENT_SUCCESS:
+               return 1;
+       default:
+               fatal("Bad response from authentication agent: %d", type);
+       }
+       /* NOTREACHED */
+       return 0;
+}
diff --git a/openssh/authfd.h b/openssh/authfd.h
new file mode 100644 (file)
index 0000000..8075a7e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions to interface with the SSH_AUTHENTICATION_FD socket.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: authfd.h,v 1.21 2001/08/07 10:37:46 markus Exp $"); */
+
+#ifndef AUTHFD_H
+#define AUTHFD_H
+
+#include "buffer.h"
+
+/* Messages for the authentication agent connection. */
+#define SSH_AGENTC_REQUEST_RSA_IDENTITIES      1
+#define SSH_AGENT_RSA_IDENTITIES_ANSWER                2
+#define SSH_AGENTC_RSA_CHALLENGE               3
+#define SSH_AGENT_RSA_RESPONSE                 4
+#define SSH_AGENT_FAILURE                      5
+#define SSH_AGENT_SUCCESS                      6
+#define SSH_AGENTC_ADD_RSA_IDENTITY            7
+#define SSH_AGENTC_REMOVE_RSA_IDENTITY         8
+#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES   9
+
+/* private OpenSSH extensions for SSH2 */
+#define SSH2_AGENTC_REQUEST_IDENTITIES         11
+#define SSH2_AGENT_IDENTITIES_ANSWER           12
+#define SSH2_AGENTC_SIGN_REQUEST               13
+#define SSH2_AGENT_SIGN_RESPONSE               14
+#define SSH2_AGENTC_ADD_IDENTITY               17
+#define SSH2_AGENTC_REMOVE_IDENTITY            18
+#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES      19
+
+/* smartcard */
+#define SSH_AGENTC_ADD_SMARTCARD_KEY           20
+#define SSH_AGENTC_REMOVE_SMARTCARD_KEY                21
+
+/* extended failure messages */
+#define SSH2_AGENT_FAILURE                     30
+
+/* additional error code for ssh.com's ssh-agent2 */
+#define SSH_COM_AGENT2_FAILURE                  102
+
+#define        SSH_AGENT_OLD_SIGNATURE                 0x01
+
+typedef struct {
+       int     fd;
+       Buffer  identities;
+       int     howmany;
+}       AuthenticationConnection;
+
+int      ssh_get_authentication_socket(void);
+void     ssh_close_authentication_socket(int);
+
+AuthenticationConnection *ssh_get_authentication_connection(void);
+void     ssh_close_authentication_connection(AuthenticationConnection *);
+int     ssh_get_num_identities(AuthenticationConnection *, int);
+Key    *ssh_get_first_identity(AuthenticationConnection *, char **, int);
+Key    *ssh_get_next_identity(AuthenticationConnection *, char **, int);
+int     ssh_add_identity(AuthenticationConnection *, Key *, const char *);
+int     ssh_remove_identity(AuthenticationConnection *, Key *);
+int     ssh_remove_all_identities(AuthenticationConnection *, int);
+int     ssh_update_card(AuthenticationConnection *, int, const char *);
+
+int
+ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16],
+    u_int, u_char[16]);
+
+int
+ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, int *, u_char *,
+    int);
+
+#endif                         /* AUTHFD_H */
diff --git a/openssh/authfile.c b/openssh/authfile.c
new file mode 100644 (file)
index 0000000..135be76
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file contains functions for reading and writing identity files, and
+ * for reading the passphrase from the user.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: authfile.c,v 1.39 2001/10/07 10:29:52 markus Exp $");
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+#include "cipher.h"
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "ssh.h"
+#include "log.h"
+#include "authfile.h"
+
+/* Version identification string for SSH v1 identity files. */
+static const char authfile_id_string[] =
+    "SSH PRIVATE KEY FILE FORMAT 1.1\n";
+
+/*
+ * Saves the authentication (private) key in a file, encrypting it with
+ * passphrase.  The identification of the file (lowest 64 bits of n) will
+ * precede the key to provide identification of the key without needing a
+ * passphrase.
+ */
+
+static int
+key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
+    const char *comment)
+{
+       Buffer buffer, encrypted;
+       char buf[100], *cp;
+       int fd, i;
+       CipherContext ciphercontext;
+       Cipher *cipher;
+       u_int32_t rand;
+
+       /*
+        * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
+        * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
+        */
+       if (strcmp(passphrase, "") == 0)
+               cipher = cipher_by_number(SSH_CIPHER_NONE);
+       else
+               cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
+       if (cipher == NULL)
+               fatal("save_private_key_rsa: bad cipher");
+
+       /* This buffer is used to built the secret part of the private key. */
+       buffer_init(&buffer);
+
+       /* Put checkbytes for checking passphrase validity. */
+       rand = arc4random();
+       buf[0] = rand & 0xff;
+       buf[1] = (rand >> 8) & 0xff;
+       buf[2] = buf[0];
+       buf[3] = buf[1];
+       buffer_append(&buffer, buf, 4);
+
+       /*
+        * Store the private key (n and e will not be stored because they
+        * will be stored in plain text, and storing them also in encrypted
+        * format would just give known plaintext).
+        */
+       buffer_put_bignum(&buffer, key->rsa->d);
+       buffer_put_bignum(&buffer, key->rsa->iqmp);
+       buffer_put_bignum(&buffer, key->rsa->q);        /* reverse from SSL p */
+       buffer_put_bignum(&buffer, key->rsa->p);        /* reverse from SSL q */
+
+       /* Pad the part to be encrypted until its size is a multiple of 8. */
+       while (buffer_len(&buffer) % 8 != 0)
+               buffer_put_char(&buffer, 0);
+
+       /* This buffer will be used to contain the data in the file. */
+       buffer_init(&encrypted);
+
+       /* First store keyfile id string. */
+       for (i = 0; authfile_id_string[i]; i++)
+               buffer_put_char(&encrypted, authfile_id_string[i]);
+       buffer_put_char(&encrypted, 0);
+
+       /* Store cipher type. */
+       buffer_put_char(&encrypted, cipher->number);
+       buffer_put_int(&encrypted, 0);  /* For future extension */
+
+       /* Store public key.  This will be in plain text. */
+       buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
+       buffer_put_bignum(&encrypted, key->rsa->n);
+       buffer_put_bignum(&encrypted, key->rsa->e);
+       buffer_put_cstring(&encrypted, comment);
+
+       /* Allocate space for the private part of the key in the buffer. */
+       buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
+
+       cipher_set_key_string(&ciphercontext, cipher, passphrase);
+       cipher_encrypt(&ciphercontext, (u_char *) cp,
+           (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
+       memset(&ciphercontext, 0, sizeof(ciphercontext));
+
+       /* Destroy temporary data. */
+       memset(buf, 0, sizeof(buf));
+       buffer_free(&buffer);
+
+       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+       if (fd < 0) {
+               error("open %s failed: %s.", filename, strerror(errno));
+               return 0;
+       }
+       if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
+           buffer_len(&encrypted)) {
+               error("write to key file %s failed: %s", filename,
+                     strerror(errno));
+               buffer_free(&encrypted);
+               close(fd);
+               unlink(filename);
+               return 0;
+       }
+       close(fd);
+       buffer_free(&encrypted);
+       return 1;
+}
+
+/* save SSH v2 key in OpenSSL PEM format */
+static int
+key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
+    const char *comment)
+{
+       FILE *fp;
+       int fd;
+       int success = 0;
+       int len = strlen(_passphrase);
+       char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
+       EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
+
+       if (len > 0 && len <= 4) {
+               error("passphrase too short: have %d bytes, need > 4", len);
+               return 0;
+       }
+       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+       if (fd < 0) {
+               error("open %s failed: %s.", filename, strerror(errno));
+               return 0;
+       }
+       fp = fdopen(fd, "w");
+       if (fp == NULL ) {
+               error("fdopen %s failed: %s.", filename, strerror(errno));
+               close(fd);
+               return 0;
+       }
+       switch (key->type) {
+       case KEY_DSA:
+               success = PEM_write_DSAPrivateKey(fp, key->dsa,
+                   cipher, passphrase, len, NULL, NULL);
+               break;
+       case KEY_RSA:
+               success = PEM_write_RSAPrivateKey(fp, key->rsa,
+                   cipher, passphrase, len, NULL, NULL);
+               break;
+       }
+       fclose(fp);
+       return success;
+}
+
+int
+key_save_private(Key *key, const char *filename, const char *passphrase,
+    const char *comment)
+{
+       switch (key->type) {
+       case KEY_RSA1:
+               return key_save_private_rsa1(key, filename, passphrase,
+                   comment);
+               break;
+       case KEY_DSA:
+       case KEY_RSA:
+               return key_save_private_pem(key, filename, passphrase,
+                   comment);
+               break;
+       default:
+               break;
+       }
+       error("key_save_private: cannot save key type %d", key->type);
+       return 0;
+}
+
+/*
+ * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
+ * encountered (the file does not exist or is not readable), and the key
+ * otherwise.
+ */
+
+static Key *
+key_load_public_rsa1(int fd, const char *filename, char **commentp)
+{
+       Buffer buffer;
+       Key *pub;
+       char *cp;
+       int i;
+       off_t len;
+
+       len = lseek(fd, (off_t) 0, SEEK_END);
+       lseek(fd, (off_t) 0, SEEK_SET);
+
+       buffer_init(&buffer);
+       buffer_append_space(&buffer, &cp, len);
+
+       if (read(fd, cp, (size_t) len) != (size_t) len) {
+               debug("Read from key file %.200s failed: %.100s", filename,
+                   strerror(errno));
+               buffer_free(&buffer);
+               return NULL;
+       }
+
+       /* Check that it is at least big enough to contain the ID string. */
+       if (len < sizeof(authfile_id_string)) {
+               debug3("Not a RSA1 key file %.200s.", filename);
+               buffer_free(&buffer);
+               return NULL;
+       }
+       /*
+        * Make sure it begins with the id string.  Consume the id string
+        * from the buffer.
+        */
+       for (i = 0; i < sizeof(authfile_id_string); i++)
+               if (buffer_get_char(&buffer) != authfile_id_string[i]) {
+                       debug3("Not a RSA1 key file %.200s.", filename);
+                       buffer_free(&buffer);
+                       return NULL;
+               }
+       /* Skip cipher type and reserved data. */
+       (void) buffer_get_char(&buffer);        /* cipher type */
+       (void) buffer_get_int(&buffer);         /* reserved */
+
+       /* Read the public key from the buffer. */
+       buffer_get_int(&buffer);
+       pub = key_new(KEY_RSA1);
+       buffer_get_bignum(&buffer, pub->rsa->n);
+       buffer_get_bignum(&buffer, pub->rsa->e);
+       if (commentp)
+               *commentp = buffer_get_string(&buffer, NULL);
+       /* The encrypted private part is not parsed by this function. */
+
+       buffer_free(&buffer);
+       return pub;
+}
+
+/* load public key from private-key file, works only for SSH v1 */
+Key *
+key_load_public_type(int type, const char *filename, char **commentp)
+{
+       Key *pub;
+       int fd;
+
+       if (type == KEY_RSA1) {
+               fd = open(filename, O_RDONLY);
+               if (fd < 0)
+                       return NULL;
+               pub = key_load_public_rsa1(fd, filename, commentp);
+               close(fd);
+               return pub;
+       }
+       return NULL;
+}
+
+/*
+ * Loads the private key from the file.  Returns 0 if an error is encountered
+ * (file does not exist or is not readable, or passphrase is bad). This
+ * initializes the private key.
+ * Assumes we are called under uid of the owner of the file.
+ */
+
+static Key *
+key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
+    char **commentp)
+{
+       int i, check1, check2, cipher_type;
+       off_t len;
+       Buffer buffer, decrypted;
+       char *cp;
+       CipherContext ciphercontext;
+       Cipher *cipher;
+       BN_CTX *ctx;
+       BIGNUM *aux;
+       Key *prv = NULL;
+
+       len = lseek(fd, (off_t) 0, SEEK_END);
+       lseek(fd, (off_t) 0, SEEK_SET);
+
+       buffer_init(&buffer);
+       buffer_append_space(&buffer, &cp, len);
+
+       if (read(fd, cp, (size_t) len) != (size_t) len) {
+               debug("Read from key file %.200s failed: %.100s", filename,
+                   strerror(errno));
+               buffer_free(&buffer);
+               close(fd);
+               return NULL;
+       }
+
+       /* Check that it is at least big enough to contain the ID string. */
+       if (len < sizeof(authfile_id_string)) {
+               debug3("Not a RSA1 key file %.200s.", filename);
+               buffer_free(&buffer);
+               close(fd);
+               return NULL;
+       }
+       /*
+        * Make sure it begins with the id string.  Consume the id string
+        * from the buffer.
+        */
+       for (i = 0; i < sizeof(authfile_id_string); i++)
+               if (buffer_get_char(&buffer) != authfile_id_string[i]) {
+                       debug3("Not a RSA1 key file %.200s.", filename);
+                       buffer_free(&buffer);
+                       close(fd);
+                       return NULL;
+               }
+
+       /* Read cipher type. */
+       cipher_type = buffer_get_char(&buffer);
+       (void) buffer_get_int(&buffer); /* Reserved data. */
+
+       /* Read the public key from the buffer. */
+       buffer_get_int(&buffer);
+       prv = key_new_private(KEY_RSA1);
+
+       buffer_get_bignum(&buffer, prv->rsa->n);
+       buffer_get_bignum(&buffer, prv->rsa->e);
+       if (commentp)
+               *commentp = buffer_get_string(&buffer, NULL);
+       else
+               xfree(buffer_get_string(&buffer, NULL));
+
+       /* Check that it is a supported cipher. */
+       cipher = cipher_by_number(cipher_type);
+       if (cipher == NULL) {
+               debug("Unsupported cipher %d used in key file %.200s.",
+                   cipher_type, filename);
+               buffer_free(&buffer);
+               goto fail;
+       }
+       /* Initialize space for decrypted data. */
+       buffer_init(&decrypted);
+       buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
+
+       /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
+       cipher_set_key_string(&ciphercontext, cipher, passphrase);
+       cipher_decrypt(&ciphercontext, (u_char *) cp,
+           (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
+       memset(&ciphercontext, 0, sizeof(ciphercontext));
+       buffer_free(&buffer);
+
+       check1 = buffer_get_char(&decrypted);
+       check2 = buffer_get_char(&decrypted);
+       if (check1 != buffer_get_char(&decrypted) ||
+           check2 != buffer_get_char(&decrypted)) {
+               if (strcmp(passphrase, "") != 0)
+                       debug("Bad passphrase supplied for key file %.200s.",
+                           filename);
+               /* Bad passphrase. */
+               buffer_free(&decrypted);
+               goto fail;
+       }
+       /* Read the rest of the private key. */
+       buffer_get_bignum(&decrypted, prv->rsa->d);
+       buffer_get_bignum(&decrypted, prv->rsa->iqmp);          /* u */
+       /* in SSL and SSH v1 p and q are exchanged */
+       buffer_get_bignum(&decrypted, prv->rsa->q);             /* p */
+       buffer_get_bignum(&decrypted, prv->rsa->p);             /* q */
+
+       /* calculate p-1 and q-1 */
+       ctx = BN_CTX_new();
+       aux = BN_new();
+
+       BN_sub(aux, prv->rsa->q, BN_value_one());
+       BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
+
+       BN_sub(aux, prv->rsa->p, BN_value_one());
+       BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
+
+       BN_clear_free(aux);
+       BN_CTX_free(ctx);
+
+       buffer_free(&decrypted);
+       close(fd);
+       return prv;
+
+fail:
+       if (commentp)
+               xfree(*commentp);
+       close(fd);
+       key_free(prv);
+       return NULL;
+}
+
+static Key *
+key_load_private_pem(int fd, int type, const char *passphrase,
+    char **commentp)
+{
+       FILE *fp;
+       EVP_PKEY *pk = NULL;
+       Key *prv = NULL;
+       char *name = "<no key>";
+
+       fp = fdopen(fd, "r");
+       if (fp == NULL) {
+               error("fdopen failed: %s", strerror(errno));
+               close(fd);
+               return NULL;
+       }
+       pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
+       if (pk == NULL) {
+               debug("PEM_read_PrivateKey failed");
+               (void)ERR_get_error();
+       } else if (pk->type == EVP_PKEY_RSA &&
+            (type == KEY_UNSPEC||type==KEY_RSA)) {
+               prv = key_new(KEY_UNSPEC);
+               prv->rsa = EVP_PKEY_get1_RSA(pk);
+               prv->type = KEY_RSA;
+               name = "rsa w/o comment";
+#ifdef DEBUG_PK
+               RSA_print_fp(stderr, prv->rsa, 8);
+#endif
+       } else if (pk->type == EVP_PKEY_DSA &&
+            (type == KEY_UNSPEC||type==KEY_DSA)) {
+               prv = key_new(KEY_UNSPEC);
+               prv->dsa = EVP_PKEY_get1_DSA(pk);
+               prv->type = KEY_DSA;
+               name = "dsa w/o comment";
+#ifdef DEBUG_PK
+               DSA_print_fp(stderr, prv->dsa, 8);
+#endif
+       } else {
+               error("PEM_read_PrivateKey: mismatch or "
+                   "unknown EVP_PKEY save_type %d", pk->save_type);
+       }
+       fclose(fp);
+       if (pk != NULL)
+               EVP_PKEY_free(pk);
+       if (prv != NULL && commentp)
+               *commentp = xstrdup(name);
+       debug("read PEM private key done: type %s",
+           prv ? key_type(prv) : "<unknown>");
+       return prv;
+}
+
+static int
+key_perm_ok(int fd, const char *filename)
+{
+       struct stat st;
+
+       if (fstat(fd, &st) < 0)
+               return 0;
+       /*
+        * if a key owned by the user is accessed, then we check the
+        * permissions of the file. if the key owned by a different user,
+        * then we don't care.
+        */
+#ifdef HAVE_CYGWIN
+       if (check_ntsec(filename))
+#endif
+       if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("Permissions 0%3.3o for '%s' are too open.",
+                   st.st_mode & 0777, filename);
+               error("It is recommended that your private key files are NOT accessible by others.");
+               error("This private key will be ignored.");
+               return 0;
+       }
+       return 1;
+}
+
+Key *
+key_load_private_type(int type, const char *filename, const char *passphrase,
+    char **commentp)
+{
+       int fd;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               return NULL;
+       if (!key_perm_ok(fd, filename)) {
+               error("bad permissions: ignore key: %s", filename);
+               close(fd);
+               return NULL;
+       }
+       switch (type) {
+       case KEY_RSA1:
+               return key_load_private_rsa1(fd, filename, passphrase,
+                   commentp);
+               /* closes fd */
+               break;
+       case KEY_DSA:
+       case KEY_RSA:
+       case KEY_UNSPEC:
+               return key_load_private_pem(fd, type, passphrase, commentp);
+               /* closes fd */
+               break;
+       default:
+               close(fd);
+               break;
+       }
+       return NULL;
+}
+
+Key *
+key_load_private(const char *filename, const char *passphrase,
+    char **commentp)
+{
+       Key *pub, *prv;
+       int fd;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               return NULL;
+       if (!key_perm_ok(fd, filename)) {
+               error("bad permissions: ignore key: %s", filename);
+               close(fd);
+               return NULL;
+       }
+       pub = key_load_public_rsa1(fd, filename, commentp);
+       lseek(fd, (off_t) 0, SEEK_SET);         /* rewind */
+       if (pub == NULL) {
+               /* closes fd */
+               prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
+               /* use the filename as a comment for PEM */
+               if (commentp && prv)
+                       *commentp = xstrdup(filename);
+       } else {
+               /* it's a SSH v1 key if the public key part is readable */
+               key_free(pub);
+               /* closes fd */
+               prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
+       }
+       return prv;
+}
+
+static int
+key_try_load_public(Key *k, const char *filename, char **commentp)
+{
+       FILE *f;
+       char line[4096];
+       char *cp;
+
+       f = fopen(filename, "r");
+       if (f != NULL) {
+               while (fgets(line, sizeof(line), f)) {
+                       line[sizeof(line)-1] = '\0';
+                       cp = line;
+                       switch(*cp){
+                       case '#':
+                       case '\n':
+                       case '\0':
+                               continue;
+                       }
+                       /* Skip leading whitespace. */
+                       for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
+                               ;
+                       if (*cp) {
+                               if (key_read(k, &cp) == 1) {
+                                       if (commentp)
+                                               *commentp=xstrdup(filename);
+                                       fclose(f);
+                                       return 1;
+                               }
+                       }
+               }
+               fclose(f);
+       }
+       return 0;
+}
+
+/* load public key from ssh v1 private or any pubkey file */
+Key *
+key_load_public(const char *filename, char **commentp)
+{
+       Key *pub;
+       char file[MAXPATHLEN];
+
+       pub = key_load_public_type(KEY_RSA1, filename, commentp);
+       if (pub != NULL)
+               return pub;
+       pub = key_new(KEY_UNSPEC);
+       if (key_try_load_public(pub, filename, commentp) == 1)
+               return pub;
+       if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
+           (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
+           (key_try_load_public(pub, file, commentp) == 1))
+               return pub;
+       key_free(pub);
+       return NULL;
+}
diff --git a/openssh/authfile.h b/openssh/authfile.h
new file mode 100644 (file)
index 0000000..c8b31fb
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* $OpenBSD: authfile.h,v 1.8 2001/06/26 17:27:22 markus Exp $ */
+
+#ifndef AUTHFILE_H
+#define AUTHFILE_H
+
+int     key_save_private(Key *, const char *, const char *, const char *);
+Key    *key_load_public(const char *, char **);
+Key    *key_load_public_type(int, const char *, char **);
+Key    *key_load_private(const char *, const char *, char **);
+Key    *key_load_private_type(int, const char *, const char *, char **);
+
+#endif
diff --git a/openssh/bufaux.c b/openssh/bufaux.c
new file mode 100644 (file)
index 0000000..b17256d
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Auxiliary functions for storing and retrieving various data types to/from
+ * Buffers.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * SSH2 packet format added by Markus Friedl
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: bufaux.c,v 1.17 2001/01/21 19:05:45 markus Exp $");
+
+#include <openssl/bn.h>
+#include "bufaux.h"
+#include "xmalloc.h"
+#include "getput.h"
+#include "log.h"
+
+/*
+ * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
+ * by (bits+7)/8 bytes of binary data, msb first.
+ */
+void
+buffer_put_bignum(Buffer *buffer, BIGNUM *value)
+{
+       int bits = BN_num_bits(value);
+       int bin_size = (bits + 7) / 8;
+       u_char *buf = xmalloc(bin_size);
+       int oi;
+       char msg[2];
+
+       /* Get the value of in binary */
+       oi = BN_bn2bin(value, buf);
+       if (oi != bin_size)
+               fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
+                     oi, bin_size);
+
+       /* Store the number of bits in the buffer in two bytes, msb first. */
+       PUT_16BIT(msg, bits);
+       buffer_append(buffer, msg, 2);
+       /* Store the binary data. */
+       buffer_append(buffer, (char *)buf, oi);
+
+       memset(buf, 0, bin_size);
+       xfree(buf);
+}
+
+/*
+ * Retrieves an BIGNUM from the buffer.
+ */
+int
+buffer_get_bignum(Buffer *buffer, BIGNUM *value)
+{
+       int bits, bytes;
+       u_char buf[2], *bin;
+
+       /* Get the number for bits. */
+       buffer_get(buffer, (char *) buf, 2);
+       bits = GET_16BIT(buf);
+       /* Compute the number of binary bytes that follow. */
+       bytes = (bits + 7) / 8;
+       if (buffer_len(buffer) < bytes)
+               fatal("buffer_get_bignum: input buffer too small");
+       bin = (u_char *) buffer_ptr(buffer);
+       BN_bin2bn(bin, bytes, value);
+       buffer_consume(buffer, bytes);
+
+       return 2 + bytes;
+}
+
+/*
+ * Stores an BIGNUM in the buffer in SSH2 format.
+ */
+void
+buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
+{
+       int bytes = BN_num_bytes(value) + 1;
+       u_char *buf = xmalloc(bytes);
+       int oi;
+       int hasnohigh = 0;
+       buf[0] = '\0';
+       /* Get the value of in binary */
+       oi = BN_bn2bin(value, buf+1);
+       if (oi != bytes-1)
+               fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
+                     oi, bytes);
+       hasnohigh = (buf[1] & 0x80) ? 0 : 1;
+       if (value->neg) {
+               /**XXX should be two's-complement */
+               int i, carry;
+               u_char *uc = buf;
+               log("negativ!");
+               for(i = bytes-1, carry = 1; i>=0; i--) {
+                       uc[i] ^= 0xff;
+                       if(carry)
+                               carry = !++uc[i];
+               }
+       }
+       buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
+       memset(buf, 0, bytes);
+       xfree(buf);
+}
+
+int
+buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
+{
+       /**XXX should be two's-complement */
+       int len;
+       u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
+       BN_bin2bn(bin, len, value);
+       xfree(bin);
+       return len;
+}
+
+/*
+ * Returns an integer from the buffer (4 bytes, msb first).
+ */
+u_int
+buffer_get_int(Buffer *buffer)
+{
+       u_char buf[4];
+       buffer_get(buffer, (char *) buf, 4);
+       return GET_32BIT(buf);
+}
+
+#ifdef HAVE_U_INT64_T
+u_int64_t
+buffer_get_int64(Buffer *buffer)
+{
+       u_char buf[8];
+       buffer_get(buffer, (char *) buf, 8);
+       return GET_64BIT(buf);
+}
+#endif
+
+/*
+ * Stores an integer in the buffer in 4 bytes, msb first.
+ */
+void
+buffer_put_int(Buffer *buffer, u_int value)
+{
+       char buf[4];
+       PUT_32BIT(buf, value);
+       buffer_append(buffer, buf, 4);
+}
+
+#ifdef HAVE_U_INT64_T
+void
+buffer_put_int64(Buffer *buffer, u_int64_t value)
+{
+       char buf[8];
+       PUT_64BIT(buf, value);
+       buffer_append(buffer, buf, 8);
+}
+#endif
+
+/*
+ * Returns an arbitrary binary string from the buffer.  The string cannot
+ * be longer than 256k.  The returned value points to memory allocated
+ * with xmalloc; it is the responsibility of the calling function to free
+ * the data.  If length_ptr is non-NULL, the length of the returned data
+ * will be stored there.  A null character will be automatically appended
+ * to the returned string, and is not counted in length.
+ */
+char *
+buffer_get_string(Buffer *buffer, u_int *length_ptr)
+{
+       u_int len;
+       char *value;
+       /* Get the length. */
+       len = buffer_get_int(buffer);
+       if (len > 256 * 1024)
+               fatal("Received packet with bad string length %d", len);
+       /* Allocate space for the string.  Add one byte for a null character. */
+       value = xmalloc(len + 1);
+       /* Get the string. */
+       buffer_get(buffer, value, len);
+       /* Append a null character to make processing easier. */
+       value[len] = 0;
+       /* Optionally return the length of the string. */
+       if (length_ptr)
+               *length_ptr = len;
+       return value;
+}
+
+/*
+ * Stores and arbitrary binary string in the buffer.
+ */
+void
+buffer_put_string(Buffer *buffer, const void *buf, u_int len)
+{
+       buffer_put_int(buffer, len);
+       buffer_append(buffer, buf, len);
+}
+void
+buffer_put_cstring(Buffer *buffer, const char *s)
+{
+       buffer_put_string(buffer, s, strlen(s));
+}
+
+/*
+ * Returns a character from the buffer (0 - 255).
+ */
+int
+buffer_get_char(Buffer *buffer)
+{
+       char ch;
+       buffer_get(buffer, &ch, 1);
+       return (u_char) ch;
+}
+
+/*
+ * Stores a character in the buffer.
+ */
+void
+buffer_put_char(Buffer *buffer, int value)
+{
+       char ch = value;
+       buffer_append(buffer, &ch, 1);
+}
diff --git a/openssh/bufaux.h b/openssh/bufaux.h
new file mode 100644 (file)
index 0000000..d1af098
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: bufaux.h,v 1.13 2001/06/26 17:27:22 markus Exp $"); */
+
+#ifndef BUFAUX_H
+#define BUFAUX_H
+
+#include "buffer.h"
+#include <openssl/bn.h>
+
+void    buffer_put_bignum(Buffer *, BIGNUM *);
+void    buffer_put_bignum2(Buffer *, BIGNUM *);
+
+int     buffer_get_bignum(Buffer *, BIGNUM *);
+int    buffer_get_bignum2(Buffer *, BIGNUM *);
+
+u_int buffer_get_int(Buffer *);
+void    buffer_put_int(Buffer *, u_int);
+
+#ifdef HAVE_U_INT64_T
+u_int64_t buffer_get_int64(Buffer *);
+void   buffer_put_int64(Buffer *, u_int64_t);
+#endif
+
+int     buffer_get_char(Buffer *);
+
+void    buffer_put_char(Buffer *, int);
+
+char   *buffer_get_string(Buffer *, u_int *);
+
+void    buffer_put_string(Buffer *, const void *, u_int);
+void   buffer_put_cstring(Buffer *, const char *);
+
+#endif                         /* BUFAUX_H */
diff --git a/openssh/buffer.c b/openssh/buffer.c
new file mode 100644 (file)
index 0000000..044caaf
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for manipulating fifo buffers (that can grow if needed).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: buffer.c,v 1.13 2001/04/12 19:15:24 markus Exp $");
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+
+/* Initializes the buffer structure. */
+
+void
+buffer_init(Buffer *buffer)
+{
+       buffer->alloc = 4096;
+       buffer->buf = xmalloc(buffer->alloc);
+       buffer->offset = 0;
+       buffer->end = 0;
+}
+
+/* Frees any memory used for the buffer. */
+
+void
+buffer_free(Buffer *buffer)
+{
+       memset(buffer->buf, 0, buffer->alloc);
+       xfree(buffer->buf);
+}
+
+/*
+ * Clears any data from the buffer, making it empty.  This does not actually
+ * zero the memory.
+ */
+
+void
+buffer_clear(Buffer *buffer)
+{
+       buffer->offset = 0;
+       buffer->end = 0;
+}
+
+/* Appends data to the buffer, expanding it if necessary. */
+
+void
+buffer_append(Buffer *buffer, const char *data, u_int len)
+{
+       char *cp;
+       buffer_append_space(buffer, &cp, len);
+       memcpy(cp, data, len);
+}
+
+/*
+ * Appends space to the buffer, expanding the buffer if necessary. This does
+ * not actually copy the data into the buffer, but instead returns a pointer
+ * to the allocated region.
+ */
+
+void
+buffer_append_space(Buffer *buffer, char **datap, u_int len)
+{
+       /* If the buffer is empty, start using it from the beginning. */
+       if (buffer->offset == buffer->end) {
+               buffer->offset = 0;
+               buffer->end = 0;
+       }
+restart:
+       /* If there is enough space to store all data, store it now. */
+       if (buffer->end + len < buffer->alloc) {
+               *datap = buffer->buf + buffer->end;
+               buffer->end += len;
+               return;
+       }
+       /*
+        * If the buffer is quite empty, but all data is at the end, move the
+        * data to the beginning and retry.
+        */
+       if (buffer->offset > buffer->alloc / 2) {
+               memmove(buffer->buf, buffer->buf + buffer->offset,
+                       buffer->end - buffer->offset);
+               buffer->end -= buffer->offset;
+               buffer->offset = 0;
+               goto restart;
+       }
+       /* Increase the size of the buffer and retry. */
+       buffer->alloc += len + 32768;
+       buffer->buf = xrealloc(buffer->buf, buffer->alloc);
+       goto restart;
+}
+
+/* Returns the number of bytes of data in the buffer. */
+
+u_int
+buffer_len(Buffer *buffer)
+{
+       return buffer->end - buffer->offset;
+}
+
+/* Gets data from the beginning of the buffer. */
+
+void
+buffer_get(Buffer *buffer, char *buf, u_int len)
+{
+       if (len > buffer->end - buffer->offset)
+               fatal("buffer_get: trying to get more bytes %d than in buffer %d",
+                   len, buffer->end - buffer->offset);
+       memcpy(buf, buffer->buf + buffer->offset, len);
+       buffer->offset += len;
+}
+
+/* Consumes the given number of bytes from the beginning of the buffer. */
+
+void
+buffer_consume(Buffer *buffer, u_int bytes)
+{
+       if (bytes > buffer->end - buffer->offset)
+               fatal("buffer_consume: trying to get more bytes than in buffer");
+       buffer->offset += bytes;
+}
+
+/* Consumes the given number of bytes from the end of the buffer. */
+
+void
+buffer_consume_end(Buffer *buffer, u_int bytes)
+{
+       if (bytes > buffer->end - buffer->offset)
+               fatal("buffer_consume_end: trying to get more bytes than in buffer");
+       buffer->end -= bytes;
+}
+
+/* Returns a pointer to the first used byte in the buffer. */
+
+char *
+buffer_ptr(Buffer *buffer)
+{
+       return buffer->buf + buffer->offset;
+}
+
+/* Dumps the contents of the buffer to stderr. */
+
+void
+buffer_dump(Buffer *buffer)
+{
+       int i;
+       u_char *ucp = (u_char *) buffer->buf;
+
+       for (i = buffer->offset; i < buffer->end; i++) {
+               fprintf(stderr, "%02x", ucp[i]);
+               if ((i-buffer->offset)%16==15)
+                       fprintf(stderr, "\r\n");
+               else if ((i-buffer->offset)%2==1)
+                       fprintf(stderr, " ");
+       }
+       fprintf(stderr, "\r\n");
+}
diff --git a/openssh/buffer.h b/openssh/buffer.h
new file mode 100644 (file)
index 0000000..845bfb6
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Code for manipulating FIFO buffers.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: buffer.h,v 1.9 2001/06/26 17:27:23 markus Exp $"); */
+
+#ifndef BUFFER_H
+#define BUFFER_H
+
+typedef struct {
+       char    *buf;           /* Buffer for data. */
+       u_int    alloc;         /* Number of bytes allocated for data. */
+       u_int    offset;        /* Offset of first byte containing data. */
+       u_int    end;           /* Offset of last byte containing data. */
+}       Buffer;
+
+void    buffer_init(Buffer *);
+void    buffer_clear(Buffer *);
+void    buffer_free(Buffer *);
+
+u_int   buffer_len(Buffer *);
+char   *buffer_ptr(Buffer *);
+
+void    buffer_append(Buffer *, const char *, u_int);
+void    buffer_append_space(Buffer *, char **, u_int);
+
+void    buffer_get(Buffer *, char *, u_int);
+
+void    buffer_consume(Buffer *, u_int);
+void    buffer_consume_end(Buffer *, u_int);
+
+void     buffer_dump(Buffer *);
+
+#endif                         /* BUFFER_H */
diff --git a/openssh/canohost.c b/openssh/canohost.c
new file mode 100644 (file)
index 0000000..6e6a045
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for returning the canonical host name of the remote site.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: canohost.c,v 1.27 2001/06/23 15:12:17 itojun Exp $");
+
+#include "packet.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "canohost.h"
+
+static void check_ip_options(int, char *);
+
+/*
+ * Return the canonical name of the host at the other end of the socket. The
+ * caller should free the returned string with xfree.
+ */
+
+static char *
+get_remote_hostname(int socket, int reverse_mapping_check)
+{
+       struct sockaddr_storage from;
+       int i;
+       socklen_t fromlen;
+       struct addrinfo hints, *ai, *aitop;
+       char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
+
+       /* Get IP address of client. */
+       fromlen = sizeof(from);
+       memset(&from, 0, sizeof(from));
+       if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
+               debug("getpeername failed: %.100s", strerror(errno));
+               fatal_cleanup();
+       }
+#ifdef IPV4_IN_IPV6
+       if (from.ss_family == AF_INET6) {
+               struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
+
+               /* Detect IPv4 in IPv6 mapped address and convert it to */
+               /* plain (AF_INET) IPv4 address */
+               if (IN6_IS_ADDR_V4MAPPED(&from6->sin6_addr)) {
+                       struct sockaddr_in *from4 = (struct sockaddr_in *)&from;
+                       struct in_addr addr;
+                       u_int16_t port;
+
+                       memcpy(&addr, ((char *)&from6->sin6_addr) + 12, sizeof(addr));
+                       port = from6->sin6_port;
+
+                       memset(&from, 0, sizeof(from));
+
+                       from4->sin_family = AF_INET;
+                       memcpy(&from4->sin_addr, &addr, sizeof(addr));
+                       from4->sin_port = port;
+               }
+       }
+#endif
+       if (from.ss_family == AF_INET)
+               check_ip_options(socket, ntop);
+
+       if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
+            NULL, 0, NI_NUMERICHOST) != 0)
+               fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
+
+       debug3("Trying to reverse map address %.100s.", ntop);
+       /* Map the IP address to a host name. */
+       if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
+            NULL, 0, NI_NAMEREQD) != 0) {
+               /* Host name not found.  Use ip address. */
+               log("Could not reverse map address %.100s.", ntop);
+               return xstrdup(ntop);
+       }
+
+       /* Got host name. */
+       name[sizeof(name) - 1] = '\0';
+       /*
+        * Convert it to all lowercase (which is expected by the rest
+        * of this software).
+        */
+       for (i = 0; name[i]; i++)
+               if (isupper(name[i]))
+                       name[i] = tolower(name[i]);
+
+       if (!reverse_mapping_check)
+               return xstrdup(name);
+       /*
+        * Map it back to an IP address and check that the given
+        * address actually is an address of this host.  This is
+        * necessary because anyone with access to a name server can
+        * define arbitrary names for an IP address. Mapping from
+        * name to IP address can be trusted better (but can still be
+        * fooled if the intruder has access to the name server of
+        * the domain).
+        */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = from.ss_family;
+       hints.ai_socktype = SOCK_STREAM;
+       if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
+               log("reverse mapping checking getaddrinfo for %.700s "
+                   "failed - POSSIBLE BREAKIN ATTEMPT!", name);
+               return xstrdup(ntop);
+       }
+       /* Look for the address from the list of addresses. */
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
+                   sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
+                   (strcmp(ntop, ntop2) == 0))
+                               break;
+       }
+       freeaddrinfo(aitop);
+       /* If we reached the end of the list, the address was not there. */
+       if (!ai) {
+               /* Address not found for the host name. */
+               log("Address %.100s maps to %.600s, but this does not "
+                   "map back to the address - POSSIBLE BREAKIN ATTEMPT!",
+                   ntop, name);
+               return xstrdup(ntop);
+       }
+       return xstrdup(name);
+}
+
+/*
+ * If IP options are supported, make sure there are none (log and
+ * disconnect them if any are found).  Basically we are worried about
+ * source routing; it can be used to pretend you are somebody
+ * (ip-address) you are not. That itself may be "almost acceptable"
+ * under certain circumstances, but rhosts autentication is useless
+ * if source routing is accepted. Notice also that if we just dropped
+ * source routing here, the other side could use IP spoofing to do
+ * rest of the interaction and could still bypass security.  So we
+ * exit here if we detect any IP options.
+ */
+/* IPv4 only */
+static void
+check_ip_options(int socket, char *ipaddr)
+{
+       u_char options[200];
+       char text[sizeof(options) * 3 + 1];
+       socklen_t option_size;
+       int i, ipproto;
+       struct protoent *ip;
+
+       if ((ip = getprotobyname("ip")) != NULL)
+               ipproto = ip->p_proto;
+       else
+               ipproto = IPPROTO_IP;
+       option_size = sizeof(options);
+       if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
+           &option_size) >= 0 && option_size != 0) {
+               text[0] = '\0';
+               for (i = 0; i < option_size; i++)
+                       snprintf(text + i*3, sizeof(text) - i*3,
+                           " %2.2x", options[i]);
+               log("Connection from %.100s with IP options:%.800s",
+                   ipaddr, text);
+               packet_disconnect("Connection from %.100s with IP options:%.800s",
+                   ipaddr, text);
+       }
+}
+
+/*
+ * Return the canonical name of the host in the other side of the current
+ * connection.  The host name is cached, so it is efficient to call this
+ * several times.
+ */
+
+const char *
+get_canonical_hostname(int reverse_mapping_check)
+{
+       static char *canonical_host_name = NULL;
+       static int reverse_mapping_checked = 0;
+
+       /* Check if we have previously retrieved name with same option. */
+       if (canonical_host_name != NULL) {
+               if (reverse_mapping_checked != reverse_mapping_check)
+                       xfree(canonical_host_name);
+               else
+                       return canonical_host_name;
+       }
+
+       /* Get the real hostname if socket; otherwise return UNKNOWN. */
+       if (packet_connection_is_on_socket())
+               canonical_host_name = get_remote_hostname(
+                   packet_get_connection_in(), reverse_mapping_check);
+       else
+               canonical_host_name = xstrdup("UNKNOWN");
+
+       reverse_mapping_checked = reverse_mapping_check;
+       return canonical_host_name;
+}
+
+/*
+ * Returns the remote IP-address of socket as a string.  The returned
+ * string must be freed.
+ */
+static char *
+get_socket_address(int socket, int remote, int flags)
+{
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       char ntop[NI_MAXHOST];
+
+       /* Get IP address of client. */
+       addrlen = sizeof(addr);
+       memset(&addr, 0, sizeof(addr));
+
+       if (remote) {
+               if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
+                   < 0) {
+                       debug("get_socket_ipaddr: getpeername failed: %.100s",
+                           strerror(errno));
+                       return NULL;
+               }
+       } else {
+               if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
+                   < 0) {
+                       debug("get_socket_ipaddr: getsockname failed: %.100s",
+                           strerror(errno));
+                       return NULL;
+               }
+       }
+       /* Get the address in ascii. */
+       if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
+            NULL, 0, flags) != 0) {
+               error("get_socket_ipaddr: getnameinfo %d failed", flags);
+               return NULL;
+       }
+       return xstrdup(ntop);
+}
+
+char *
+get_peer_ipaddr(int socket)
+{
+       return get_socket_address(socket, 1, NI_NUMERICHOST);
+}
+
+char *
+get_local_ipaddr(int socket)
+{
+       return get_socket_address(socket, 0, NI_NUMERICHOST);
+}
+
+char *
+get_local_name(int socket)
+{
+       return get_socket_address(socket, 0, NI_NAMEREQD);
+}
+
+/*
+ * Returns the IP-address of the remote host as a string.  The returned
+ * string must not be freed.
+ */
+
+const char *
+get_remote_ipaddr()
+{
+       static char *canonical_host_ip = NULL;
+
+       /* Check whether we have cached the ipaddr. */
+       if (canonical_host_ip == NULL) {
+               if (packet_connection_is_on_socket()) {
+                       canonical_host_ip =
+                           get_peer_ipaddr(packet_get_connection_in());
+                       if (canonical_host_ip == NULL)
+                               fatal_cleanup();
+               } else {
+                       /* If not on socket, return UNKNOWN. */
+                       canonical_host_ip = xstrdup("UNKNOWN");
+               }
+       }
+       return canonical_host_ip;
+}
+
+const char *
+get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
+{
+       static const char *remote = "";
+       if (utmp_len > 0)
+               remote = get_canonical_hostname(reverse_mapping_check);
+       if (utmp_len == 0 || strlen(remote) > utmp_len)
+               remote = get_remote_ipaddr();
+       return remote;
+}
+
+/* Returns the local/remote port for the socket. */
+
+static int
+get_sock_port(int sock, int local)
+{
+       struct sockaddr_storage from;
+       socklen_t fromlen;
+       char strport[NI_MAXSERV];
+
+       /* Get IP address of client. */
+       fromlen = sizeof(from);
+       memset(&from, 0, sizeof(from));
+       if (local) {
+               if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
+                       error("getsockname failed: %.100s", strerror(errno));
+                       return 0;
+               }
+       } else {
+               if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
+                       debug("getpeername failed: %.100s", strerror(errno));
+                       fatal_cleanup();
+               }
+       }
+       /* Return port number. */
+       if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
+            strport, sizeof(strport), NI_NUMERICSERV) != 0)
+               fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
+       return atoi(strport);
+}
+
+/* Returns remote/local port number for the current connection. */
+
+static int
+get_port(int local)
+{
+       /*
+        * If the connection is not a socket, return 65535.  This is
+        * intentionally chosen to be an unprivileged port number.
+        */
+       if (!packet_connection_is_on_socket())
+               return 65535;
+
+       /* Get socket and return the port number. */
+       return get_sock_port(packet_get_connection_in(), local);
+}
+
+int
+get_peer_port(int sock)
+{
+       return get_sock_port(sock, 0);
+}
+
+int
+get_remote_port()
+{
+       return get_port(0);
+}
+
+int
+get_local_port()
+{
+       return get_port(1);
+}
diff --git a/openssh/canohost.h b/openssh/canohost.h
new file mode 100644 (file)
index 0000000..4347b48
--- /dev/null
@@ -0,0 +1,25 @@
+/*     $OpenBSD: canohost.h,v 1.8 2001/06/26 17:27:23 markus Exp $     */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+const char     *get_canonical_hostname(int);
+const char     *get_remote_ipaddr(void);
+const char     *get_remote_name_or_ip(u_int, int);
+
+char           *get_peer_ipaddr(int);
+int             get_peer_port(int);
+char           *get_local_ipaddr(int);
+char           *get_local_name(int);
+
+int             get_remote_port(void);
+int             get_local_port(void);
diff --git a/openssh/channels.c b/openssh/channels.c
new file mode 100644 (file)
index 0000000..62fd73d
--- /dev/null
@@ -0,0 +1,2978 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file contains functions for generic socket connection forwarding.
+ * There is also code for initiating connection forwarding for X11 connections,
+ * arbitrary tcp/ip connections, and the authentication agent connection.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * SSH2 support added by Markus Friedl.
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 1999 Dug Song.  All rights reserved.
+ * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: channels.c,v 1.140 2001/10/10 22:18:47 markus Exp $");
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "uidswap.h"
+#include "log.h"
+#include "misc.h"
+#include "channels.h"
+#include "compat.h"
+#include "canohost.h"
+#include "key.h"
+#include "authfd.h"
+
+
+/* -- channel core */
+
+/*
+ * Pointer to an array containing all allocated channels.  The array is
+ * dynamically extended as needed.
+ */
+static Channel **channels = NULL;
+
+/*
+ * Size of the channel array.  All slots of the array must always be
+ * initialized (at least the type field); unused slots set to NULL
+ */
+static int channels_alloc = 0;
+
+/*
+ * Maximum file descriptor value used in any of the channels.  This is
+ * updated in channel_new.
+ */
+static int channel_max_fd = 0;
+
+
+/* -- tcp forwarding */
+
+/*
+ * Data structure for storing which hosts are permitted for forward requests.
+ * The local sides of any remote forwards are stored in this array to prevent
+ * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
+ * network (which might be behind a firewall).
+ */
+typedef struct {
+       char *host_to_connect;          /* Connect to 'host'. */
+       u_short port_to_connect;        /* Connect to 'port'. */
+       u_short listen_port;            /* Remote side should listen port number. */
+} ForwardPermission;
+
+/* List of all permitted host/port pairs to connect. */
+static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
+
+/* Number of permitted host/port pairs in the array. */
+static int num_permitted_opens = 0;
+/*
+ * If this is true, all opens are permitted.  This is the case on the server
+ * on which we have to trust the client anyway, and the user could do
+ * anything after logging in anyway.
+ */
+static int all_opens_permitted = 0;
+
+
+/* -- X11 forwarding */
+
+/* Maximum number of fake X11 displays to try. */
+#define MAX_DISPLAYS  1000
+
+/* Saved X11 authentication protocol name. */
+static char *x11_saved_proto = NULL;
+
+/* Saved X11 authentication data.  This is the real data. */
+static char *x11_saved_data = NULL;
+static u_int x11_saved_data_len = 0;
+
+/*
+ * Fake X11 authentication data.  This is what the server will be sending us;
+ * we should replace any occurrences of this by the real data.
+ */
+static char *x11_fake_data = NULL;
+static u_int x11_fake_data_len;
+
+
+/* -- agent forwarding */
+
+#define        NUM_SOCKS       10
+
+/* Name and directory of socket for authentication agent forwarding. */
+static char *auth_sock_name = NULL;
+static char *auth_sock_dir = NULL;
+
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+static int IPv4or6 = AF_UNSPEC;
+
+/* helper */
+static void port_open_helper(Channel *c, char *rtype);
+
+/* -- channel core */
+
+Channel *
+channel_lookup(int id)
+{
+       Channel *c;
+
+       if (id < 0 || id > channels_alloc) {
+               log("channel_lookup: %d: bad id", id);
+               return NULL;
+       }
+       c = channels[id];
+       if (c == NULL) {
+               log("channel_lookup: %d: bad id: channel free", id);
+               return NULL;
+       }
+       return c;
+}
+
+/*
+ * Register filedescriptors for a channel, used when allocating a channel or
+ * when the channel consumer/producer is ready, e.g. shell exec'd
+ */
+
+static void
+channel_register_fds(Channel *c, int rfd, int wfd, int efd,
+    int extusage, int nonblock)
+{
+       /* Update the maximum file descriptor value. */
+       channel_max_fd = MAX(channel_max_fd, rfd);
+       channel_max_fd = MAX(channel_max_fd, wfd);
+       channel_max_fd = MAX(channel_max_fd, efd);
+
+       /* XXX set close-on-exec -markus */
+
+       c->rfd = rfd;
+       c->wfd = wfd;
+       c->sock = (rfd == wfd) ? rfd : -1;
+       c->efd = efd;
+       c->extended_usage = extusage;
+
+       /* XXX ugly hack: nonblock is only set by the server */
+       if (nonblock && isatty(c->rfd)) {
+               debug("channel %d: rfd %d isatty", c->self, c->rfd);
+               c->isatty = 1;
+               if (!isatty(c->wfd)) {
+                       error("channel %d: wfd %d is not a tty?",
+                           c->self, c->wfd);
+               }
+       } else {
+               c->isatty = 0;
+       }
+
+       /* enable nonblocking mode */
+       if (nonblock) {
+               if (rfd != -1)
+                       set_nonblock(rfd);
+               if (wfd != -1)
+                       set_nonblock(wfd);
+               if (efd != -1)
+                       set_nonblock(efd);
+       }
+}
+
+/*
+ * Allocate a new channel object and set its type and socket. This will cause
+ * remote_name to be freed.
+ */
+
+Channel *
+channel_new(char *ctype, int type, int rfd, int wfd, int efd,
+    int window, int maxpack, int extusage, char *remote_name, int nonblock)
+{
+       int i, found;
+       Channel *c;
+
+       /* Do initial allocation if this is the first call. */
+       if (channels_alloc == 0) {
+               chan_init();
+               channels_alloc = 10;
+               channels = xmalloc(channels_alloc * sizeof(Channel *));
+               for (i = 0; i < channels_alloc; i++)
+                       channels[i] = NULL;
+               fatal_add_cleanup((void (*) (void *)) channel_free_all, NULL);
+       }
+       /* Try to find a free slot where to put the new channel. */
+       for (found = -1, i = 0; i < channels_alloc; i++)
+               if (channels[i] == NULL) {
+                       /* Found a free slot. */
+                       found = i;
+                       break;
+               }
+       if (found == -1) {
+               /* There are no free slots.  Take last+1 slot and expand the array.  */
+               found = channels_alloc;
+               channels_alloc += 10;
+               debug2("channel: expanding %d", channels_alloc);
+               channels = xrealloc(channels, channels_alloc * sizeof(Channel *));
+               for (i = found; i < channels_alloc; i++)
+                       channels[i] = NULL;
+       }
+       /* Initialize and return new channel. */
+       c = channels[found] = xmalloc(sizeof(Channel));
+       memset(c, 0, sizeof(Channel));
+       buffer_init(&c->input);
+       buffer_init(&c->output);
+       buffer_init(&c->extended);
+       chan_init_iostates(c);
+       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
+       c->self = found;
+       c->type = type;
+       c->ctype = ctype;
+       c->local_window = window;
+       c->local_window_max = window;
+       c->local_consumed = 0;
+       c->local_maxpacket = maxpack;
+       c->remote_id = -1;
+       c->remote_name = remote_name;
+       c->remote_window = 0;
+       c->remote_maxpacket = 0;
+       c->cb_fn = NULL;
+       c->cb_arg = NULL;
+       c->cb_event = 0;
+       c->force_drain = 0;
+       c->detach_user = NULL;
+       c->input_filter = NULL;
+       debug("channel %d: new [%s]", found, remote_name);
+       return c;
+}
+
+static int
+channel_find_maxfd(void)
+{
+       int i, max = 0;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c != NULL) {
+                       max = MAX(max, c->rfd);
+                       max = MAX(max, c->wfd);
+                       max = MAX(max, c->efd);
+               }
+       }
+       return max;
+}
+
+int
+channel_close_fd(int *fdp)
+{
+       int ret = 0, fd = *fdp;
+
+       if (fd != -1) {
+               ret = close(fd);
+               *fdp = -1;
+               if (fd == channel_max_fd)
+                       channel_max_fd = channel_find_maxfd();
+       }
+       return ret;
+}
+
+/* Close all channel fd/socket. */
+
+static void
+channel_close_fds(Channel *c)
+{
+       debug3("channel_close_fds: channel %d: r %d w %d e %d",
+           c->self, c->rfd, c->wfd, c->efd);
+
+       channel_close_fd(&c->sock);
+       channel_close_fd(&c->rfd);
+       channel_close_fd(&c->wfd);
+       channel_close_fd(&c->efd);
+}
+
+/* Free the channel and close its fd/socket. */
+
+void
+channel_free(Channel *c)
+{
+       char *s;
+       int i, n;
+
+       for (n = 0, i = 0; i < channels_alloc; i++)
+               if (channels[i])
+                       n++;
+       debug("channel_free: channel %d: %s, nchannels %d", c->self,
+           c->remote_name ? c->remote_name : "???", n);
+
+       s = channel_open_message();
+       debug3("channel_free: status: %s", s);
+       xfree(s);
+
+       if (c->sock != -1)
+               shutdown(c->sock, SHUT_RDWR);
+       channel_close_fds(c);
+       buffer_free(&c->input);
+       buffer_free(&c->output);
+       buffer_free(&c->extended);
+       if (c->remote_name) {
+               xfree(c->remote_name);
+               c->remote_name = NULL;
+       }
+       channels[c->self] = NULL;
+       xfree(c);
+}
+
+void
+channel_free_all(void)
+{
+       int i;
+
+       for (i = 0; i < channels_alloc; i++)
+               if (channels[i] != NULL)
+                       channel_free(channels[i]);
+}
+
+/*
+ * Closes the sockets/fds of all channels.  This is used to close extra file
+ * descriptors after a fork.
+ */
+
+void
+channel_close_all()
+{
+       int i;
+
+       for (i = 0; i < channels_alloc; i++)
+               if (channels[i] != NULL)
+                       channel_close_fds(channels[i]);
+}
+
+/*
+ * Stop listening to channels.
+ */
+
+void
+channel_stop_listening(void)
+{
+       int i;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c != NULL) {
+                       switch (c->type) {
+                       case SSH_CHANNEL_AUTH_SOCKET:
+                       case SSH_CHANNEL_PORT_LISTENER:
+                       case SSH_CHANNEL_RPORT_LISTENER:
+                       case SSH_CHANNEL_X11_LISTENER:
+                               channel_close_fd(&c->sock);
+                               channel_free(c);
+                               break;
+                       }
+               }
+       }
+}
+
+/*
+ * Returns true if no channel has too much buffered data, and false if one or
+ * more channel is overfull.
+ */
+
+int
+channel_not_very_much_buffered_data()
+{
+       u_int i;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
+#if 0
+                       if (!compat20 &&
+                           buffer_len(&c->input) > packet_get_maxsize()) {
+                               debug("channel %d: big input buffer %d",
+                                   c->self, buffer_len(&c->input));
+                               return 0;
+                       }
+#endif
+                       if (buffer_len(&c->output) > packet_get_maxsize()) {
+                               debug("channel %d: big output buffer %d > %d",
+                                   c->self, buffer_len(&c->output),
+                                   packet_get_maxsize());
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+
+/* Returns true if any channel is still open. */
+
+int
+channel_still_open()
+{
+       int i;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c == NULL)
+                       continue;
+               switch (c->type) {
+               case SSH_CHANNEL_X11_LISTENER:
+               case SSH_CHANNEL_PORT_LISTENER:
+               case SSH_CHANNEL_RPORT_LISTENER:
+               case SSH_CHANNEL_CLOSED:
+               case SSH_CHANNEL_AUTH_SOCKET:
+               case SSH_CHANNEL_DYNAMIC:
+               case SSH_CHANNEL_CONNECTING:
+               case SSH_CHANNEL_ZOMBIE:
+                       continue;
+               case SSH_CHANNEL_LARVAL:
+                       if (!compat20)
+                               fatal("cannot happen: SSH_CHANNEL_LARVAL");
+                       continue;
+               case SSH_CHANNEL_OPENING:
+               case SSH_CHANNEL_OPEN:
+               case SSH_CHANNEL_X11_OPEN:
+                       return 1;
+               case SSH_CHANNEL_INPUT_DRAINING:
+               case SSH_CHANNEL_OUTPUT_DRAINING:
+                       if (!compat13)
+                               fatal("cannot happen: OUT_DRAIN");
+                       return 1;
+               default:
+                       fatal("channel_still_open: bad channel type %d", c->type);
+                       /* NOTREACHED */
+               }
+       }
+       return 0;
+}
+
+/* Returns the id of an open channel suitable for keepaliving */
+
+int
+channel_find_open()
+{
+       int i;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c == NULL)
+                       continue;
+               switch (c->type) {
+               case SSH_CHANNEL_CLOSED:
+               case SSH_CHANNEL_DYNAMIC:
+               case SSH_CHANNEL_X11_LISTENER:
+               case SSH_CHANNEL_PORT_LISTENER:
+               case SSH_CHANNEL_RPORT_LISTENER:
+               case SSH_CHANNEL_OPENING:
+               case SSH_CHANNEL_CONNECTING:
+               case SSH_CHANNEL_ZOMBIE:
+                       continue;
+               case SSH_CHANNEL_LARVAL:
+               case SSH_CHANNEL_AUTH_SOCKET:
+               case SSH_CHANNEL_OPEN:
+               case SSH_CHANNEL_X11_OPEN:
+                       return i;
+               case SSH_CHANNEL_INPUT_DRAINING:
+               case SSH_CHANNEL_OUTPUT_DRAINING:
+                       if (!compat13)
+                               fatal("cannot happen: OUT_DRAIN");
+                       return i;
+               default:
+                       fatal("channel_find_open: bad channel type %d", c->type);
+                       /* NOTREACHED */
+               }
+       }
+       return -1;
+}
+
+
+/*
+ * Returns a message describing the currently open forwarded connections,
+ * suitable for sending to the client.  The message contains crlf pairs for
+ * newlines.
+ */
+
+char *
+channel_open_message()
+{
+       Buffer buffer;
+       Channel *c;
+       char buf[1024], *cp;
+       int i;
+
+       buffer_init(&buffer);
+       snprintf(buf, sizeof buf, "The following connections are open:\r\n");
+       buffer_append(&buffer, buf, strlen(buf));
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c == NULL)
+                       continue;
+               switch (c->type) {
+               case SSH_CHANNEL_X11_LISTENER:
+               case SSH_CHANNEL_PORT_LISTENER:
+               case SSH_CHANNEL_RPORT_LISTENER:
+               case SSH_CHANNEL_CLOSED:
+               case SSH_CHANNEL_AUTH_SOCKET:
+               case SSH_CHANNEL_ZOMBIE:
+                       continue;
+               case SSH_CHANNEL_LARVAL:
+               case SSH_CHANNEL_OPENING:
+               case SSH_CHANNEL_CONNECTING:
+               case SSH_CHANNEL_DYNAMIC:
+               case SSH_CHANNEL_OPEN:
+               case SSH_CHANNEL_X11_OPEN:
+               case SSH_CHANNEL_INPUT_DRAINING:
+               case SSH_CHANNEL_OUTPUT_DRAINING:
+                       snprintf(buf, sizeof buf, "  #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
+                           c->self, c->remote_name,
+                           c->type, c->remote_id,
+                           c->istate, buffer_len(&c->input),
+                           c->ostate, buffer_len(&c->output),
+                           c->rfd, c->wfd);
+                       buffer_append(&buffer, buf, strlen(buf));
+                       continue;
+               default:
+                       fatal("channel_open_message: bad channel type %d", c->type);
+                       /* NOTREACHED */
+               }
+       }
+       buffer_append(&buffer, "\0", 1);
+       cp = xstrdup(buffer_ptr(&buffer));
+       buffer_free(&buffer);
+       return cp;
+}
+
+void
+channel_send_open(int id)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL) {
+               log("channel_send_open: %d: bad id", id);
+               return;
+       }
+       debug("send channel open %d", id);
+       packet_start(SSH2_MSG_CHANNEL_OPEN);
+       packet_put_cstring(c->ctype);
+       packet_put_int(c->self);
+       packet_put_int(c->local_window);
+       packet_put_int(c->local_maxpacket);
+       packet_send();
+}
+
+void
+channel_request(int id, char *service, int wantconfirm)
+{
+       channel_request_start(id, service, wantconfirm);
+       packet_send();
+       debug("channel request %d: %s", id, service) ;
+}
+void
+channel_request_start(int id, char *service, int wantconfirm)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL) {
+               log("channel_request: %d: bad id", id);
+               return;
+       }
+       packet_start(SSH2_MSG_CHANNEL_REQUEST);
+       packet_put_int(c->remote_id);
+       packet_put_cstring(service);
+       packet_put_char(wantconfirm);
+}
+void
+channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL) {
+               log("channel_register_callback: %d: bad id", id);
+               return;
+       }
+       c->cb_event = mtype;
+       c->cb_fn = fn;
+       c->cb_arg = arg;
+}
+void
+channel_register_cleanup(int id, channel_callback_fn *fn)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL) {
+               log("channel_register_cleanup: %d: bad id", id);
+               return;
+       }
+       c->detach_user = fn;
+}
+void
+channel_cancel_cleanup(int id)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL) {
+               log("channel_cancel_cleanup: %d: bad id", id);
+               return;
+       }
+       c->detach_user = NULL;
+}
+void
+channel_register_filter(int id, channel_filter_fn *fn)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL) {
+               log("channel_register_filter: %d: bad id", id);
+               return;
+       }
+       c->input_filter = fn;
+}
+
+void
+channel_set_fds(int id, int rfd, int wfd, int efd,
+    int extusage, int nonblock)
+{
+       Channel *c = channel_lookup(id);
+       if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
+               fatal("channel_activate for non-larval channel %d.", id);
+       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
+       c->type = SSH_CHANNEL_OPEN;
+       /* XXX window size? */
+       c->local_window = c->local_window_max = c->local_maxpacket * 2;
+       packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+       packet_put_int(c->remote_id);
+       packet_put_int(c->local_window);
+       packet_send();
+}
+
+/*
+ * 'channel_pre*' are called just before select() to add any bits relevant to
+ * channels in the select bitmasks.
+ */
+/*
+ * 'channel_post*': perform any appropriate operations for channels which
+ * have events pending.
+ */
+typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);
+chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
+chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
+
+static void
+channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       FD_SET(c->sock, readset);
+}
+
+static void
+channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       debug3("channel %d: waiting for connection", c->self);
+       FD_SET(c->sock, writeset);
+}
+
+static void
+channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       if (buffer_len(&c->input) < packet_get_maxsize())
+               FD_SET(c->sock, readset);
+       if (buffer_len(&c->output) > 0)
+               FD_SET(c->sock, writeset);
+}
+
+static void
+channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       /* test whether sockets are 'alive' for read/write */
+       if (c->istate == CHAN_INPUT_OPEN)
+               if (buffer_len(&c->input) < packet_get_maxsize())
+                       FD_SET(c->sock, readset);
+       if (c->ostate == CHAN_OUTPUT_OPEN ||
+           c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+               if (buffer_len(&c->output) > 0) {
+                       FD_SET(c->sock, writeset);
+               } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+                       chan_obuf_empty(c);
+               }
+       }
+}
+
+static void
+channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       if (c->istate == CHAN_INPUT_OPEN &&
+           c->remote_window > 0 &&
+           buffer_len(&c->input) < c->remote_window)
+               FD_SET(c->rfd, readset);
+       if (c->ostate == CHAN_OUTPUT_OPEN ||
+           c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+               if (buffer_len(&c->output) > 0) {
+                       FD_SET(c->wfd, writeset);
+               } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+                       chan_obuf_empty(c);
+               }
+       }
+       /** XXX check close conditions, too */
+       if (c->efd != -1) {
+               if (c->extended_usage == CHAN_EXTENDED_WRITE &&
+                   buffer_len(&c->extended) > 0)
+                       FD_SET(c->efd, writeset);
+               else if (c->extended_usage == CHAN_EXTENDED_READ &&
+                   buffer_len(&c->extended) < c->remote_window)
+                       FD_SET(c->efd, readset);
+       }
+}
+
+static void
+channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       if (buffer_len(&c->input) == 0) {
+               packet_start(SSH_MSG_CHANNEL_CLOSE);
+               packet_put_int(c->remote_id);
+               packet_send();
+               c->type = SSH_CHANNEL_CLOSED;
+               debug("channel %d: closing after input drain.", c->self);
+       }
+}
+
+static void
+channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       if (buffer_len(&c->output) == 0)
+               chan_mark_dead(c);
+       else
+               FD_SET(c->sock, writeset);
+}
+
+/*
+ * This is a special state for X11 authentication spoofing.  An opened X11
+ * connection (when authentication spoofing is being done) remains in this
+ * state until the first packet has been completely read.  The authentication
+ * data in that packet is then substituted by the real data if it matches the
+ * fake data, and the channel is put into normal mode.
+ * XXX All this happens at the client side.
+ * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
+ */
+static int
+x11_open_helper(Buffer *b)
+{
+       u_char *ucp;
+       u_int proto_len, data_len;
+
+       /* Check if the fixed size part of the packet is in buffer. */
+       if (buffer_len(b) < 12)
+               return 0;
+
+       /* Parse the lengths of variable-length fields. */
+       ucp = (u_char *) buffer_ptr(b);
+       if (ucp[0] == 0x42) {   /* Byte order MSB first. */
+               proto_len = 256 * ucp[6] + ucp[7];
+               data_len = 256 * ucp[8] + ucp[9];
+       } else if (ucp[0] == 0x6c) {    /* Byte order LSB first. */
+               proto_len = ucp[6] + 256 * ucp[7];
+               data_len = ucp[8] + 256 * ucp[9];
+       } else {
+               debug("Initial X11 packet contains bad byte order byte: 0x%x",
+                     ucp[0]);
+               return -1;
+       }
+
+       /* Check if the whole packet is in buffer. */
+       if (buffer_len(b) <
+           12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
+               return 0;
+
+       /* Check if authentication protocol matches. */
+       if (proto_len != strlen(x11_saved_proto) ||
+           memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
+               debug("X11 connection uses different authentication protocol.");
+               return -1;
+       }
+       /* Check if authentication data matches our fake data. */
+       if (data_len != x11_fake_data_len ||
+           memcmp(ucp + 12 + ((proto_len + 3) & ~3),
+               x11_fake_data, x11_fake_data_len) != 0) {
+               debug("X11 auth data does not match fake data.");
+               return -1;
+       }
+       /* Check fake data length */
+       if (x11_fake_data_len != x11_saved_data_len) {
+               error("X11 fake_data_len %d != saved_data_len %d",
+                   x11_fake_data_len, x11_saved_data_len);
+               return -1;
+       }
+       /*
+        * Received authentication protocol and data match
+        * our fake data. Substitute the fake data with real
+        * data.
+        */
+       memcpy(ucp + 12 + ((proto_len + 3) & ~3),
+           x11_saved_data, x11_saved_data_len);
+       return 1;
+}
+
+static void
+channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       int ret = x11_open_helper(&c->output);
+       if (ret == 1) {
+               /* Start normal processing for the channel. */
+               c->type = SSH_CHANNEL_OPEN;
+               channel_pre_open_13(c, readset, writeset);
+       } else if (ret == -1) {
+               /*
+                * We have received an X11 connection that has bad
+                * authentication information.
+                */
+               log("X11 connection rejected because of wrong authentication.");
+               buffer_clear(&c->input);
+               buffer_clear(&c->output);
+               channel_close_fd(&c->sock);
+               c->sock = -1;
+               c->type = SSH_CHANNEL_CLOSED;
+               packet_start(SSH_MSG_CHANNEL_CLOSE);
+               packet_put_int(c->remote_id);
+               packet_send();
+       }
+}
+
+static void
+channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       int ret = x11_open_helper(&c->output);
+
+       /* c->force_drain = 1; */
+
+       if (ret == 1) {
+               c->type = SSH_CHANNEL_OPEN;
+               if (compat20)
+                       channel_pre_open_20(c, readset, writeset);
+               else
+                       channel_pre_open_15(c, readset, writeset);
+       } else if (ret == -1) {
+               debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
+               chan_read_failed(c);    /** force close? */
+               chan_write_failed(c);
+               debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
+       }
+}
+
+/* try to decode a socks4 header */
+static int
+channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       u_char *p, *host;
+       int len, have, i, found;
+       char username[256];     
+       struct {
+               u_int8_t version;
+               u_int8_t command;
+               u_int16_t dest_port;
+               struct in_addr dest_addr;
+       } s4_req, s4_rsp;
+
+       debug2("channel %d: decode socks4", c->self);
+
+       have = buffer_len(&c->input);
+       len = sizeof(s4_req);
+       if (have < len)
+               return 0;
+       p = buffer_ptr(&c->input);
+       for (found = 0, i = len; i < have; i++) {
+               if (p[i] == '\0') {
+                       found = 1;
+                       break;
+               }
+               if (i > 1024) {
+                       /* the peer is probably sending garbage */
+                       debug("channel %d: decode socks4: too long",
+                           c->self);
+                       return -1;
+               }
+       }
+       if (!found)
+               return 0;
+       buffer_get(&c->input, (char *)&s4_req.version, 1);
+       buffer_get(&c->input, (char *)&s4_req.command, 1);
+       buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
+       buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
+       have = buffer_len(&c->input);
+       p = buffer_ptr(&c->input);
+       len = strlen(p);
+       debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
+       if (len > have)
+               fatal("channel %d: decode socks4: len %d > have %d",
+                   c->self, len, have);
+       strlcpy(username, p, sizeof(username));
+       buffer_consume(&c->input, len);
+       buffer_consume(&c->input, 1);           /* trailing '\0' */
+
+       host = inet_ntoa(s4_req.dest_addr);
+       strlcpy(c->path, host, sizeof(c->path));
+       c->host_port = ntohs(s4_req.dest_port);
+       
+       debug("channel %d: dynamic request: socks4 host %s port %u command %u",
+           c->self, host, c->host_port, s4_req.command);
+
+       if (s4_req.command != 1) {
+               debug("channel %d: cannot handle: socks4 cn %d",
+                   c->self, s4_req.command);
+               return -1;
+       }
+       s4_rsp.version = 0;                     /* vn: 0 for reply */
+       s4_rsp.command = 90;                    /* cd: req granted */
+       s4_rsp.dest_port = 0;                   /* ignored */
+       s4_rsp.dest_addr.s_addr = INADDR_ANY;   /* ignored */
+       buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp));
+       return 1;
+}
+
+/* dynamic port forwarding */
+static void
+channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       u_char *p;
+       int have, ret;
+
+       have = buffer_len(&c->input);
+       c->delayed = 0;
+       debug2("channel %d: pre_dynamic: have %d", c->self, have);
+       /* buffer_dump(&c->input); */
+       /* check if the fixed size part of the packet is in buffer. */
+       if (have < 4) {
+               /* need more */
+               FD_SET(c->sock, readset);
+               return;
+       }
+       /* try to guess the protocol */
+       p = buffer_ptr(&c->input);
+       switch (p[0]) {
+       case 0x04:
+               ret = channel_decode_socks4(c, readset, writeset);
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       if (ret < 0) {
+               chan_mark_dead(c);
+       } else if (ret == 0) {
+               debug2("channel %d: pre_dynamic: need more", c->self);
+               /* need more */
+               FD_SET(c->sock, readset);
+       } else {
+               /* switch to the next state */
+               c->type = SSH_CHANNEL_OPENING;
+               port_open_helper(c, "direct-tcpip");
+       }
+}
+
+/* This is our fake X11 server socket. */
+static void
+channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       Channel *nc;
+       struct sockaddr addr;
+       int newsock;
+       socklen_t addrlen;
+       char buf[16384], *remote_ipaddr;
+       int remote_port;
+
+       if (FD_ISSET(c->sock, readset)) {
+               debug("X11 connection requested.");
+               addrlen = sizeof(addr);
+               newsock = accept(c->sock, &addr, &addrlen);
+               if (newsock < 0) {
+                       error("accept: %.100s", strerror(errno));
+                       return;
+               }
+               remote_ipaddr = get_peer_ipaddr(newsock);
+               remote_port = get_peer_port(newsock);
+               snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
+                   remote_ipaddr, remote_port);
+
+               nc = channel_new("accepted x11 socket",
+                   SSH_CHANNEL_OPENING, newsock, newsock, -1,
+                   c->local_window_max, c->local_maxpacket,
+                   0, xstrdup(buf), 1);
+               if (nc == NULL) {
+                       close(newsock);
+                       xfree(remote_ipaddr);
+                       return;
+               }
+               if (compat20) {
+                       packet_start(SSH2_MSG_CHANNEL_OPEN);
+                       packet_put_cstring("x11");
+                       packet_put_int(nc->self);
+                       packet_put_int(c->local_window_max);
+                       packet_put_int(c->local_maxpacket);
+                       /* originator ipaddr and port */
+                       packet_put_cstring(remote_ipaddr);
+                       if (datafellows & SSH_BUG_X11FWD) {
+                               debug("ssh2 x11 bug compat mode");
+                       } else {
+                               packet_put_int(remote_port);
+                       }
+                       packet_send();
+               } else {
+                       packet_start(SSH_SMSG_X11_OPEN);
+                       packet_put_int(nc->self);
+                       if (packet_get_protocol_flags() &
+                           SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
+                               packet_put_cstring(buf);
+                       packet_send();
+               }
+               xfree(remote_ipaddr);
+       }
+}
+
+static void
+port_open_helper(Channel *c, char *rtype)
+{
+       int direct;
+       char buf[1024];
+       char *remote_ipaddr = get_peer_ipaddr(c->sock);
+       u_short remote_port = get_peer_port(c->sock);
+
+       direct = (strcmp(rtype, "direct-tcpip") == 0);
+
+       snprintf(buf, sizeof buf,
+           "%s: listening port %d for %.100s port %d, "
+           "connect from %.200s port %d",
+           rtype, c->listening_port, c->path, c->host_port,
+           remote_ipaddr, remote_port);
+
+       xfree(c->remote_name);
+       c->remote_name = xstrdup(buf);
+
+       if (compat20) {
+               packet_start(SSH2_MSG_CHANNEL_OPEN);
+               packet_put_cstring(rtype);
+               packet_put_int(c->self);
+               packet_put_int(c->local_window_max);
+               packet_put_int(c->local_maxpacket);
+               if (direct) {
+                       /* target host, port */
+                       packet_put_cstring(c->path);
+                       packet_put_int(c->host_port);
+               } else {
+                       /* listen address, port */
+                       packet_put_cstring(c->path);
+                       packet_put_int(c->listening_port);
+               }
+               /* originator host and port */
+               packet_put_cstring(remote_ipaddr);
+               packet_put_int(remote_port);
+               packet_send();
+       } else {
+               packet_start(SSH_MSG_PORT_OPEN);
+               packet_put_int(c->self);
+               packet_put_cstring(c->path);
+               packet_put_int(c->host_port);
+               if (packet_get_protocol_flags() &
+                   SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
+                       packet_put_cstring(c->remote_name);
+               packet_send();
+       }
+       xfree(remote_ipaddr);
+}
+
+/*
+ * This socket is listening for connections to a forwarded TCP/IP port.
+ */
+static void
+channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       Channel *nc;
+       struct sockaddr addr;
+       int newsock, nextstate;
+       socklen_t addrlen;
+       char *rtype;
+
+       if (FD_ISSET(c->sock, readset)) {
+               debug("Connection to port %d forwarding "
+                   "to %.100s port %d requested.",
+                   c->listening_port, c->path, c->host_port);
+
+               if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
+                       nextstate = SSH_CHANNEL_OPENING;
+                       rtype = "forwarded-tcpip";
+               } else {
+                       if (c->host_port == 0) {
+                               nextstate = SSH_CHANNEL_DYNAMIC;
+                               rtype = "dynamic-tcpip";
+                       } else {
+                               nextstate = SSH_CHANNEL_OPENING;
+                               rtype = "direct-tcpip";
+                       }
+               }
+
+               addrlen = sizeof(addr);
+               newsock = accept(c->sock, &addr, &addrlen);
+               if (newsock < 0) {
+                       error("accept: %.100s", strerror(errno));
+                       return;
+               }
+               nc = channel_new(rtype,
+                   nextstate, newsock, newsock, -1,
+                   c->local_window_max, c->local_maxpacket,
+                   0, xstrdup(rtype), 1);
+               if (nc == NULL) {
+                       error("channel_post_port_listener: no new channel:");
+                       close(newsock);
+                       return;
+               }
+               nc->listening_port = c->listening_port;
+               nc->host_port = c->host_port;
+               strlcpy(nc->path, c->path, sizeof(nc->path));
+
+               if (nextstate == SSH_CHANNEL_DYNAMIC) {
+                       /*
+                        * do not call the channel_post handler until
+                        * this flag has been reset by a pre-handler.
+                        * otherwise the FD_ISSET calls might overflow
+                        */
+                       nc->delayed = 1;
+               } else {
+                       port_open_helper(nc, rtype);
+               }
+       }
+}
+
+/*
+ * This is the authentication agent socket listening for connections from
+ * clients.
+ */
+static void
+channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       Channel *nc;
+       char *name;
+       int newsock;
+       struct sockaddr addr;
+       socklen_t addrlen;
+
+       if (FD_ISSET(c->sock, readset)) {
+               addrlen = sizeof(addr);
+               newsock = accept(c->sock, &addr, &addrlen);
+               if (newsock < 0) {
+                       error("accept from auth socket: %.100s", strerror(errno));
+                       return;
+               }
+               name = xstrdup("accepted auth socket");
+               nc = channel_new("accepted auth socket",
+                   SSH_CHANNEL_OPENING, newsock, newsock, -1,
+                   c->local_window_max, c->local_maxpacket,
+                   0, name, 1);
+               if (nc == NULL) {
+                       error("channel_post_auth_listener: channel_new failed");
+                       xfree(name);
+                       close(newsock);
+               }
+               if (compat20) {
+                       packet_start(SSH2_MSG_CHANNEL_OPEN);
+                       packet_put_cstring("auth-agent@openssh.com");
+                       packet_put_int(nc->self);
+                       packet_put_int(c->local_window_max);
+                       packet_put_int(c->local_maxpacket);
+               } else {
+                       packet_start(SSH_SMSG_AGENT_OPEN);
+                       packet_put_int(nc->self);
+               }
+               packet_send();
+       }
+}
+
+static void
+channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       int err = 0;
+       socklen_t sz = sizeof(err);
+
+       if (FD_ISSET(c->sock, writeset)) {
+               if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err,
+                   &sz) < 0) {
+                       err = errno;
+                       error("getsockopt SO_ERROR failed");
+               }
+               if (err == 0) {
+                       debug("channel %d: connected", c->self);
+                       c->type = SSH_CHANNEL_OPEN;
+                       if (compat20) {
+                               packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+                               packet_put_int(c->remote_id);
+                               packet_put_int(c->self);
+                               packet_put_int(c->local_window);
+                               packet_put_int(c->local_maxpacket);
+                       } else {
+                               packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+                               packet_put_int(c->remote_id);
+                               packet_put_int(c->self);
+                       }
+               } else {
+                       debug("channel %d: not connected: %s",
+                           c->self, strerror(err));
+                       if (compat20) {
+                               packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+                               packet_put_int(c->remote_id);
+                               packet_put_int(SSH2_OPEN_CONNECT_FAILED);
+                               if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+                                       packet_put_cstring(strerror(err));
+                                       packet_put_cstring("");
+                               }
+                       } else {
+                               packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+                               packet_put_int(c->remote_id);
+                       }
+                       chan_mark_dead(c);
+               }
+               packet_send();
+       }
+}
+
+static int
+channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       char buf[16*1024];
+       int len;
+
+       if (c->rfd != -1 &&
+           FD_ISSET(c->rfd, readset)) {
+               len = read(c->rfd, buf, sizeof(buf));
+               if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                       return 1;
+               if (len <= 0) {
+                       debug("channel %d: read<=0 rfd %d len %d",
+                           c->self, c->rfd, len);
+                       if (c->type != SSH_CHANNEL_OPEN) {
+                               debug("channel %d: not open", c->self);
+                               chan_mark_dead(c);
+                               return -1;
+                       } else if (compat13) {
+                               buffer_consume(&c->output, buffer_len(&c->output));
+                               c->type = SSH_CHANNEL_INPUT_DRAINING;
+                               debug("channel %d: input draining.", c->self);
+                       } else {
+                               chan_read_failed(c);
+                       }
+                       return -1;
+               }
+               if(c->input_filter != NULL) {
+                       if (c->input_filter(c, buf, len) == -1) {
+                               debug("channel %d: filter stops", c->self);
+                               chan_read_failed(c);
+                       }
+               } else {
+                       buffer_append(&c->input, buf, len);
+               }
+       }
+       return 1;
+}
+static int
+channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       struct termios tio;
+       u_char *data;
+       u_int dlen;
+       int len;
+
+       /* Send buffered output data to the socket. */
+       if (c->wfd != -1 &&
+           FD_ISSET(c->wfd, writeset) &&
+           buffer_len(&c->output) > 0) {
+               data = buffer_ptr(&c->output);
+               dlen = buffer_len(&c->output);
+               len = write(c->wfd, data, dlen);
+               if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                       return 1;
+               if (len <= 0) {
+                       if (c->type != SSH_CHANNEL_OPEN) {
+                               debug("channel %d: not open", c->self);
+                               chan_mark_dead(c);
+                               return -1;
+                       } else if (compat13) {
+                               buffer_consume(&c->output, buffer_len(&c->output));
+                               debug("channel %d: input draining.", c->self);
+                               c->type = SSH_CHANNEL_INPUT_DRAINING;
+                       } else {
+                               chan_write_failed(c);
+                       }
+                       return -1;
+               }
+               if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') {
+                       if (tcgetattr(c->wfd, &tio) == 0 &&
+                           !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
+                               /*
+                                * Simulate echo to reduce the impact of
+                                * traffic analysis. We need to match the
+                                * size of a SSH2_MSG_CHANNEL_DATA message
+                                * (4 byte channel id + data)
+                                */
+                               packet_send_ignore(4 + len);
+                               packet_send();
+                       }
+               }
+               buffer_consume(&c->output, len);
+               if (compat20 && len > 0) {
+                       c->local_consumed += len;
+               }
+       }
+       return 1;
+}
+static int
+channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       char buf[16*1024];
+       int len;
+
+/** XXX handle drain efd, too */
+       if (c->efd != -1) {
+               if (c->extended_usage == CHAN_EXTENDED_WRITE &&
+                   FD_ISSET(c->efd, writeset) &&
+                   buffer_len(&c->extended) > 0) {
+                       len = write(c->efd, buffer_ptr(&c->extended),
+                           buffer_len(&c->extended));
+                       debug2("channel %d: written %d to efd %d",
+                           c->self, len, c->efd);
+                       if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                               return 1;
+                       if (len <= 0) {
+                               debug2("channel %d: closing write-efd %d",
+                                   c->self, c->efd);
+                               channel_close_fd(&c->efd);
+                       } else {
+                               buffer_consume(&c->extended, len);
+                               c->local_consumed += len;
+                       }
+               } else if (c->extended_usage == CHAN_EXTENDED_READ &&
+                   FD_ISSET(c->efd, readset)) {
+                       len = read(c->efd, buf, sizeof(buf));
+                       debug2("channel %d: read %d from efd %d",
+                            c->self, len, c->efd);
+                       if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                               return 1;
+                       if (len <= 0) {
+                               debug2("channel %d: closing read-efd %d",
+                                   c->self, c->efd);
+                               channel_close_fd(&c->efd);
+                       } else {
+                               buffer_append(&c->extended, buf, len);
+                       }
+               }
+       }
+       return 1;
+}
+static int
+channel_check_window(Channel *c)
+{
+       if (c->type == SSH_CHANNEL_OPEN &&
+           !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
+           c->local_window < c->local_window_max/2 &&
+           c->local_consumed > 0) {
+               packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+               packet_put_int(c->remote_id);
+               packet_put_int(c->local_consumed);
+               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_consumed = 0;
+       }
+       return 1;
+}
+
+static void
+channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       if (c->delayed)
+               return;
+       channel_handle_rfd(c, readset, writeset);
+       channel_handle_wfd(c, readset, writeset);
+}
+
+static void
+channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       if (c->delayed)
+               return;
+       channel_handle_rfd(c, readset, writeset);
+       channel_handle_wfd(c, readset, writeset);
+       channel_handle_efd(c, readset, writeset);
+
+       channel_check_window(c);
+}
+
+static void
+channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       int len;
+       /* Send buffered output data to the socket. */
+       if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
+               len = write(c->sock, buffer_ptr(&c->output),
+                           buffer_len(&c->output));
+               if (len <= 0)
+                       buffer_consume(&c->output, buffer_len(&c->output));
+               else
+                       buffer_consume(&c->output, len);
+       }
+}
+
+static void
+channel_handler_init_20(void)
+{
+       channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open_20;
+       channel_pre[SSH_CHANNEL_X11_OPEN] =             &channel_pre_x11_open;
+       channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_RPORT_LISTENER] =       &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
+
+       channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_2;
+       channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
+       channel_post[SSH_CHANNEL_RPORT_LISTENER] =      &channel_post_port_listener;
+       channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
+       channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
+       channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_open_2;
+}
+
+static void
+channel_handler_init_13(void)
+{
+       channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open_13;
+       channel_pre[SSH_CHANNEL_X11_OPEN] =             &channel_pre_x11_open_13;
+       channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_INPUT_DRAINING] =       &channel_pre_input_draining;
+       channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =      &channel_pre_output_draining;
+       channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
+
+       channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
+       channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
+       channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
+       channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
+       channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =     &channel_post_output_drain_13;
+       channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_open_1;
+}
+
+static void
+channel_handler_init_15(void)
+{
+       channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open_15;
+       channel_pre[SSH_CHANNEL_X11_OPEN] =             &channel_pre_x11_open;
+       channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
+
+       channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
+       channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
+       channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
+       channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
+       channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_open_1;
+}
+
+static void
+channel_handler_init(void)
+{
+       int i;
+       for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
+               channel_pre[i] = NULL;
+               channel_post[i] = NULL;
+       }
+       if (compat20)
+               channel_handler_init_20();
+       else if (compat13)
+               channel_handler_init_13();
+       else
+               channel_handler_init_15();
+}
+
+/* gc dead channels */
+static void
+channel_garbage_collect(Channel *c)
+{
+       if (c == NULL)
+               return;
+       if (c->detach_user != NULL) {
+               if (!chan_is_dead(c, 0))
+                       return;
+               debug("channel %d: gc: notify user", c->self);
+               c->detach_user(c->self, NULL);
+               /* if we still have a callback */
+               if (c->detach_user != NULL)
+                       return;
+               debug("channel %d: gc: user detached", c->self);
+       }
+       if (!chan_is_dead(c, 1))
+               return;
+       debug("channel %d: garbage collecting", c->self);
+       channel_free(c);
+}
+
+static void
+channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
+{
+       static int did_init = 0;
+       int i;
+       Channel *c;
+
+       if (!did_init) {
+               channel_handler_init();
+               did_init = 1;
+       }
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c == NULL)
+                       continue;
+               if (ftab[c->type] != NULL)
+                       (*ftab[c->type])(c, readset, writeset);
+               channel_garbage_collect(c);
+       }
+}
+
+/*
+ * Allocate/update select bitmasks and add any bits relevant to channels in
+ * select bitmasks.
+ */
+void
+channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
+    int *nallocp, int rekeying)
+{
+       int n;
+       u_int sz;
+
+       n = MAX(*maxfdp, channel_max_fd);
+
+       sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
+       /* perhaps check sz < nalloc/2 and shrink? */
+       if (*readsetp == NULL || sz > *nallocp) {
+               *readsetp = xrealloc(*readsetp, sz);
+               *writesetp = xrealloc(*writesetp, sz);
+               *nallocp = sz;
+       }
+       *maxfdp = n;
+       memset(*readsetp, 0, sz);
+       memset(*writesetp, 0, sz);
+
+       if (!rekeying)
+               channel_handler(channel_pre, *readsetp, *writesetp);
+}
+
+/*
+ * After select, perform any appropriate operations for channels which have
+ * events pending.
+ */
+void
+channel_after_select(fd_set * readset, fd_set * writeset)
+{
+       channel_handler(channel_post, readset, writeset);
+}
+
+
+/* If there is data to send to the connection, enqueue some of it now. */
+
+void
+channel_output_poll()
+{
+       int len, i;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c == NULL)
+                       continue;
+
+               /*
+                * We are only interested in channels that can have buffered
+                * incoming data.
+                */
+               if (compat13) {
+                       if (c->type != SSH_CHANNEL_OPEN &&
+                           c->type != SSH_CHANNEL_INPUT_DRAINING)
+                               continue;
+               } else {
+                       if (c->type != SSH_CHANNEL_OPEN)
+                               continue;
+               }
+               if (compat20 &&
+                   (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
+                       /* XXX is this true? */
+                       debug3("channel %d: will not send data after close", c->self);
+                       continue;
+               }
+
+               /* Get the amount of buffered data for this channel. */
+               if ((c->istate == CHAN_INPUT_OPEN ||
+                   c->istate == CHAN_INPUT_WAIT_DRAIN) &&
+                   (len = buffer_len(&c->input)) > 0) {
+                       /*
+                        * Send some data for the other side over the secure
+                        * connection.
+                        */
+                       if (compat20) {
+                               if (len > c->remote_window)
+                                       len = c->remote_window;
+                               if (len > c->remote_maxpacket)
+                                       len = c->remote_maxpacket;
+                       } else {
+                               if (packet_is_interactive()) {
+                                       if (len > 1024)
+                                               len = 512;
+                               } else {
+                                       /* Keep the packets at reasonable size. */
+                                       if (len > packet_get_maxsize()/2)
+                                               len = packet_get_maxsize()/2;
+                               }
+                       }
+                       if (len > 0) {
+                               packet_start(compat20 ?
+                                   SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
+                               packet_put_int(c->remote_id);
+                               packet_put_string(buffer_ptr(&c->input), len);
+                               packet_send();
+                               buffer_consume(&c->input, len);
+                               c->remote_window -= len;
+                       }
+               } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
+                       if (compat13)
+                               fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
+                       /*
+                        * input-buffer is empty and read-socket shutdown:
+                        * tell peer, that we will not send more data: send IEOF
+                        */
+                       chan_ibuf_empty(c);
+               }
+               /* Send extended data, i.e. stderr */
+               if (compat20 &&
+                   c->remote_window > 0 &&
+                   (len = buffer_len(&c->extended)) > 0 &&
+                   c->extended_usage == CHAN_EXTENDED_READ) {
+                       debug2("channel %d: rwin %d elen %d euse %d",
+                           c->self, c->remote_window, buffer_len(&c->extended),
+                           c->extended_usage);
+                       if (len > c->remote_window)
+                               len = c->remote_window;
+                       if (len > c->remote_maxpacket)
+                               len = c->remote_maxpacket;
+                       packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
+                       packet_put_int(c->remote_id);
+                       packet_put_int(SSH2_EXTENDED_DATA_STDERR);
+                       packet_put_string(buffer_ptr(&c->extended), len);
+                       packet_send();
+                       buffer_consume(&c->extended, len);
+                       c->remote_window -= len;
+                       debug2("channel %d: sent ext data %d", c->self, len);
+               }
+       }
+}
+
+
+/* -- protocol input */
+
+void
+channel_input_data(int type, int plen, void *ctxt)
+{
+       int id;
+       char *data;
+       u_int data_len;
+       Channel *c;
+
+       /* Get the channel number and verify it. */
+       id = packet_get_int();
+       c = channel_lookup(id);
+       if (c == NULL)
+               packet_disconnect("Received data for nonexistent channel %d.", id);
+
+       /* Ignore any data for non-open channels (might happen on close) */
+       if (c->type != SSH_CHANNEL_OPEN &&
+           c->type != SSH_CHANNEL_X11_OPEN)
+               return;
+
+       /* same for protocol 1.5 if output end is no longer open */
+       if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN)
+               return;
+
+       /* Get the data. */
+       data = packet_get_string(&data_len);
+       packet_done();
+
+       if (compat20){
+               if (data_len > c->local_maxpacket) {
+                       log("channel %d: rcvd big packet %d, maxpack %d",
+                           c->self, data_len, c->local_maxpacket);
+               }
+               if (data_len > c->local_window) {
+                       log("channel %d: rcvd too much data %d, win %d",
+                           c->self, data_len, c->local_window);
+                       xfree(data);
+                       return;
+               }
+               c->local_window -= data_len;
+       }else{
+               packet_integrity_check(plen, 4 + 4 + data_len, type);
+       }
+       buffer_append(&c->output, data, data_len);
+       xfree(data);
+}
+
+void
+channel_input_extended_data(int type, int plen, void *ctxt)
+{
+       int id;
+       int tcode;
+       char *data;
+       u_int data_len;
+       Channel *c;
+
+       /* Get the channel number and verify it. */
+       id = packet_get_int();
+       c = channel_lookup(id);
+
+       if (c == NULL)
+               packet_disconnect("Received extended_data for bad channel %d.", id);
+       if (c->type != SSH_CHANNEL_OPEN) {
+               log("channel %d: ext data for non open", id);
+               return;
+       }
+       tcode = packet_get_int();
+       if (c->efd == -1 ||
+           c->extended_usage != CHAN_EXTENDED_WRITE ||
+           tcode != SSH2_EXTENDED_DATA_STDERR) {
+               log("channel %d: bad ext data", c->self);
+               return;
+       }
+       data = packet_get_string(&data_len);
+       packet_done();
+       if (data_len > c->local_window) {
+               log("channel %d: rcvd too much extended_data %d, win %d",
+                   c->self, data_len, c->local_window);
+               xfree(data);
+               return;
+       }
+       debug2("channel %d: rcvd ext data %d", c->self, data_len);
+       c->local_window -= data_len;
+       buffer_append(&c->extended, data, data_len);
+       xfree(data);
+}
+
+void
+channel_input_ieof(int type, int plen, void *ctxt)
+{
+       int id;
+       Channel *c;
+
+       packet_integrity_check(plen, 4, type);
+
+       id = packet_get_int();
+       c = channel_lookup(id);
+       if (c == NULL)
+               packet_disconnect("Received ieof for nonexistent channel %d.", id);
+       chan_rcvd_ieof(c);
+
+       /* XXX force input close */
+       if (c->force_drain) {
+               debug("channel %d: FORCE input drain", c->self);
+               c->istate = CHAN_INPUT_WAIT_DRAIN;
+       }
+
+}
+
+void
+channel_input_close(int type, int plen, void *ctxt)
+{
+       int id;
+       Channel *c;
+
+       packet_integrity_check(plen, 4, type);
+
+       id = packet_get_int();
+       c = channel_lookup(id);
+       if (c == NULL)
+               packet_disconnect("Received close for nonexistent channel %d.", id);
+
+       /*
+        * Send a confirmation that we have closed the channel and no more
+        * data is coming for it.
+        */
+       packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
+       packet_put_int(c->remote_id);
+       packet_send();
+
+       /*
+        * If the channel is in closed state, we have sent a close request,
+        * and the other side will eventually respond with a confirmation.
+        * Thus, we cannot free the channel here, because then there would be
+        * no-one to receive the confirmation.  The channel gets freed when
+        * the confirmation arrives.
+        */
+       if (c->type != SSH_CHANNEL_CLOSED) {
+               /*
+                * Not a closed channel - mark it as draining, which will
+                * cause it to be freed later.
+                */
+               buffer_consume(&c->input, buffer_len(&c->input));
+               c->type = SSH_CHANNEL_OUTPUT_DRAINING;
+       }
+}
+
+/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
+void
+channel_input_oclose(int type, int plen, void *ctxt)
+{
+       int id = packet_get_int();
+       Channel *c = channel_lookup(id);
+       packet_integrity_check(plen, 4, type);
+       if (c == NULL)
+               packet_disconnect("Received oclose for nonexistent channel %d.", id);
+       chan_rcvd_oclose(c);
+}
+
+void
+channel_input_close_confirmation(int type, int plen, void *ctxt)
+{
+       int id = packet_get_int();
+       Channel *c = channel_lookup(id);
+
+       packet_done();
+       if (c == NULL)
+               packet_disconnect("Received close confirmation for "
+                   "out-of-range channel %d.", id);
+       if (c->type != SSH_CHANNEL_CLOSED)
+               packet_disconnect("Received close confirmation for "
+                   "non-closed channel %d (type %d).", id, c->type);
+       channel_free(c);
+}
+
+void
+channel_input_open_confirmation(int type, int plen, void *ctxt)
+{
+       int id, remote_id;
+       Channel *c;
+
+       if (!compat20)
+               packet_integrity_check(plen, 4 + 4, type);
+
+       id = packet_get_int();
+       c = channel_lookup(id);
+
+       if (c==NULL || c->type != SSH_CHANNEL_OPENING)
+               packet_disconnect("Received open confirmation for "
+                   "non-opening channel %d.", id);
+       remote_id = packet_get_int();
+       /* Record the remote channel number and mark that the channel is now open. */
+       c->remote_id = remote_id;
+       c->type = SSH_CHANNEL_OPEN;
+
+       if (compat20) {
+               c->remote_window = packet_get_int();
+               c->remote_maxpacket = packet_get_int();
+               packet_done();
+               if (c->cb_fn != NULL && c->cb_event == type) {
+                       debug2("callback start");
+                       c->cb_fn(c->self, c->cb_arg);
+                       debug2("callback done");
+               }
+               debug("channel %d: open confirm rwindow %d rmax %d", c->self,
+                   c->remote_window, c->remote_maxpacket);
+       }
+}
+
+static char *
+reason2txt(int reason)
+{
+       switch(reason) {
+       case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
+               return "administratively prohibited";
+       case SSH2_OPEN_CONNECT_FAILED:
+               return "connect failed";
+       case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
+               return "unknown channel type";
+       case SSH2_OPEN_RESOURCE_SHORTAGE:
+               return "resource shortage";
+       }
+       return "unknown reason";
+}
+
+void
+channel_input_open_failure(int type, int plen, void *ctxt)
+{
+       int id, reason;
+       char *msg = NULL, *lang = NULL;
+       Channel *c;
+
+       if (!compat20)
+               packet_integrity_check(plen, 4, type);
+
+       id = packet_get_int();
+       c = channel_lookup(id);
+
+       if (c==NULL || c->type != SSH_CHANNEL_OPENING)
+               packet_disconnect("Received open failure for "
+                   "non-opening channel %d.", id);
+       if (compat20) {
+               reason = packet_get_int();
+               if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+                       msg  = packet_get_string(NULL);
+                       lang = packet_get_string(NULL);
+               }
+               packet_done();
+               log("channel %d: open failed: %s%s%s", id,
+                   reason2txt(reason), msg ? ": ": "", msg ? msg : "");
+               if (msg != NULL)
+                       xfree(msg);
+               if (lang != NULL)
+                       xfree(lang);
+       }
+       /* Free the channel.  This will also close the socket. */
+       channel_free(c);
+}
+
+void
+channel_input_channel_request(int type, int plen, void *ctxt)
+{
+       int id;
+       Channel *c;
+
+       id = packet_get_int();
+       c = channel_lookup(id);
+
+       if (c == NULL ||
+           (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL))
+               packet_disconnect("Received request for "
+                   "non-open channel %d.", id);
+       if (c->cb_fn != NULL && c->cb_event == type) {
+               debug2("callback start");
+               c->cb_fn(c->self, c->cb_arg);
+               debug2("callback done");
+       } else {
+               char *service = packet_get_string(NULL);
+               debug("channel %d: rcvd request for %s", c->self, service);
+               debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event);
+               xfree(service);
+       }
+}
+
+void
+channel_input_window_adjust(int type, int plen, void *ctxt)
+{
+       Channel *c;
+       int id, adjust;
+
+       if (!compat20)
+               return;
+
+       /* Get the channel number and verify it. */
+       id = packet_get_int();
+       c = channel_lookup(id);
+
+       if (c == NULL || c->type != SSH_CHANNEL_OPEN) {
+               log("Received window adjust for "
+                   "non-open channel %d.", id);
+               return;
+       }
+       adjust = packet_get_int();
+       packet_done();
+       debug2("channel %d: rcvd adjust %d", id, adjust);
+       c->remote_window += adjust;
+}
+
+void
+channel_input_port_open(int type, int plen, void *ctxt)
+{
+       Channel *c = NULL;
+       u_short host_port;
+       char *host, *originator_string;
+       int remote_id, sock = -1;
+
+       remote_id = packet_get_int();
+       host = packet_get_string(NULL);
+       host_port = packet_get_int();
+
+       if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
+               originator_string = packet_get_string(NULL);
+       } else {
+               originator_string = xstrdup("unknown (remote did not supply name)");
+       }
+       packet_done();
+       sock = channel_connect_to(host, host_port);
+       if (sock != -1) {
+               c = channel_new("connected socket",
+                   SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
+                   originator_string, 1);
+               if (c == NULL) {
+                       error("channel_input_port_open: channel_new failed");
+                       close(sock);
+               } else {
+                       c->remote_id = remote_id;
+               }
+       }
+       if (c == NULL) {
+               packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+               packet_put_int(remote_id);
+               packet_send();
+       }
+       xfree(host);
+}
+
+
+/* -- tcp forwarding */
+
+void
+channel_set_af(int af)
+{
+       IPv4or6 = af;
+}
+
+/*
+ * Initiate forwarding of connections to local port "port" through the secure
+ * channel to host:port from remote side.
+ */
+int
+channel_request_local_forwarding(u_short listen_port, const char *host_to_connect,
+    u_short port_to_connect, int gateway_ports)
+{
+       return channel_request_forwarding(
+           NULL, listen_port,
+           host_to_connect, port_to_connect,
+           gateway_ports, /*remote_fwd*/ 0);
+}
+
+/*
+ * If 'remote_fwd' is true we have a '-R style' listener for protocol 2
+ * (SSH_CHANNEL_RPORT_LISTENER).
+ */
+int
+channel_request_forwarding(
+    const char *listen_address, u_short listen_port,
+    const char *host_to_connect, u_short port_to_connect,
+    int gateway_ports, int remote_fwd)
+{
+       Channel *c;
+       int success, sock, on = 1, type;
+       struct addrinfo hints, *ai, *aitop;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       const char *host;
+       struct linger linger;
+
+       success = 0;
+
+       if (remote_fwd) {
+               host = listen_address;
+               type = SSH_CHANNEL_RPORT_LISTENER;
+       } else {
+               host = host_to_connect;
+               type = SSH_CHANNEL_PORT_LISTENER;
+       }
+
+       if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {
+               error("Forward host name too long.");
+               return success;
+       }
+
+       /* XXX listen_address is currently ignored */
+       /*
+        * getaddrinfo returns a loopback address if the hostname is
+        * set to NULL and hints.ai_flags is not AI_PASSIVE
+        */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_flags = gateway_ports ? AI_PASSIVE : 0;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", listen_port);
+       if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
+               packet_disconnect("getaddrinfo: fatal error");
+
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                       continue;
+               if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
+                   strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                       error("channel_request_forwarding: getnameinfo failed");
+                       continue;
+               }
+               /* Create a port to listen for the host. */
+               sock = socket(ai->ai_family, SOCK_STREAM, 0);
+               if (sock < 0) {
+                       /* this is no error since kernel may not support ipv6 */
+                       verbose("socket: %.100s", strerror(errno));
+                       continue;
+               }
+               /*
+                * Set socket options.  We would like the socket to disappear
+                * as soon as it has been closed for whatever reason.
+                */
+               setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
+               linger.l_onoff = 1;
+               linger.l_linger = 5;
+               setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
+               debug("Local forwarding listening on %s port %s.", ntop, strport);
+
+               /* Bind the socket to the address. */
+               if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       /* address can be in use ipv6 address is already bound */
+                       if (!ai->ai_next)
+                               error("bind: %.100s", strerror(errno));
+                       else
+                               verbose("bind: %.100s", strerror(errno));
+
+                       close(sock);
+                       continue;
+               }
+               /* Start listening for connections on the socket. */
+               if (listen(sock, 5) < 0) {
+                       error("listen: %.100s", strerror(errno));
+                       close(sock);
+                       continue;
+               }
+               /* Allocate a channel number for the socket. */
+               c = channel_new("port listener", type, sock, sock, -1,
+                   CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+                   0, xstrdup("port listener"), 1);
+               if (c == NULL) {
+                       error("channel_request_forwarding: channel_new failed");
+                       close(sock);
+                       continue;
+               }
+               strlcpy(c->path, host, sizeof(c->path));
+               c->host_port = port_to_connect;
+               c->listening_port = listen_port;
+               success = 1;
+       }
+       if (success == 0)
+               error("channel_request_forwarding: cannot listen to port: %d",
+                   listen_port);
+       freeaddrinfo(aitop);
+       return success;
+}
+
+/*
+ * Initiate forwarding of connections to port "port" on remote host through
+ * the secure channel to host:port from local side.
+ */
+
+void
+channel_request_remote_forwarding(u_short listen_port,
+    const char *host_to_connect, u_short port_to_connect)
+{
+       int payload_len, type, success = 0;
+
+       /* Record locally that connection to this host/port is permitted. */
+       if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
+               fatal("channel_request_remote_forwarding: too many forwards");
+
+       /* Send the forward request to the remote side. */
+       if (compat20) {
+               const char *address_to_bind = "0.0.0.0";
+               packet_start(SSH2_MSG_GLOBAL_REQUEST);
+               packet_put_cstring("tcpip-forward");
+               packet_put_char(0);                     /* boolean: want reply */
+               packet_put_cstring(address_to_bind);
+               packet_put_int(listen_port);
+               packet_send();
+               packet_write_wait();
+               /* Assume that server accepts the request */
+               success = 1;
+       } else {
+               packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
+               packet_put_int(listen_port);
+               packet_put_cstring(host_to_connect);
+               packet_put_int(port_to_connect);
+               packet_send();
+               packet_write_wait();
+
+               /* Wait for response from the remote side. */
+               type = packet_read(&payload_len);
+               switch (type) {
+               case SSH_SMSG_SUCCESS:
+                       success = 1;
+                       break;
+               case SSH_SMSG_FAILURE:
+                       log("Warning: Server denied remote port forwarding.");
+                       break;
+               default:
+                       /* Unknown packet */
+                       packet_disconnect("Protocol error for port forward request:"
+                           "received packet type %d.", type);
+               }
+       }
+       if (success) {
+               permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
+               permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
+               permitted_opens[num_permitted_opens].listen_port = listen_port;
+               num_permitted_opens++;
+       }
+}
+
+/*
+ * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
+ * listening for the port, and sends back a success reply (or disconnect
+ * message if there was an error).  This never returns if there was an error.
+ */
+
+void
+channel_input_port_forward_request(int is_root, int gateway_ports)
+{
+       u_short port, host_port;
+       char *hostname;
+
+       /* Get arguments from the packet. */
+       port = packet_get_int();
+       hostname = packet_get_string(NULL);
+       host_port = packet_get_int();
+
+#ifndef HAVE_CYGWIN
+       /*
+        * Check that an unprivileged user is not trying to forward a
+        * privileged port.
+        */
+       if (port < IPPORT_RESERVED && !is_root)
+               packet_disconnect("Requested forwarding of port %d but user is not root.",
+                                 port);
+#endif
+       /* Initiate forwarding */
+       channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
+
+       /* Free the argument string. */
+       xfree(hostname);
+}
+
+/*
+ * Permits opening to any host/port if permitted_opens[] is empty.  This is
+ * usually called by the server, because the user could connect to any port
+ * anyway, and the server has no way to know but to trust the client anyway.
+ */
+void
+channel_permit_all_opens()
+{
+       if (num_permitted_opens == 0)
+               all_opens_permitted = 1;
+}
+
+void
+channel_add_permitted_opens(char *host, int port)
+{
+       if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
+               fatal("channel_request_remote_forwarding: too many forwards");
+       debug("allow port forwarding to host %s port %d", host, port);
+
+       permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
+       permitted_opens[num_permitted_opens].port_to_connect = port;
+       num_permitted_opens++;
+
+       all_opens_permitted = 0;
+}
+
+void
+channel_clear_permitted_opens(void)
+{
+       int i;
+
+       for (i = 0; i < num_permitted_opens; i++)
+               xfree(permitted_opens[i].host_to_connect);
+       num_permitted_opens = 0;
+
+}
+
+
+/* return socket to remote host, port */
+static int
+connect_to(const char *host, u_short port)
+{
+       struct addrinfo hints, *ai, *aitop;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       int gaierr;
+       int sock = -1;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", port);
+       if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
+               error("connect_to %.100s: unknown host (%s)", host,
+                   gai_strerror(gaierr));
+               return -1;
+       }
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                       continue;
+               if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
+                   strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                       error("connect_to: getnameinfo failed");
+                       continue;
+               }
+               sock = socket(ai->ai_family, SOCK_STREAM, 0);
+               if (sock < 0) {
+                       error("socket: %.100s", strerror(errno));
+                       continue;
+               }
+               if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
+                       fatal("connect_to: F_SETFL: %s", strerror(errno));
+               if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 &&
+                   errno != EINPROGRESS) {
+                       error("connect_to %.100s port %s: %.100s", ntop, strport,
+                           strerror(errno));
+                       close(sock);
+                       continue;       /* fail -- try next */
+               }
+               break; /* success */
+
+       }
+       freeaddrinfo(aitop);
+       if (!ai) {
+               error("connect_to %.100s port %d: failed.", host, port);
+               return -1;
+       }
+       /* success */
+       return sock;
+}
+
+int
+channel_connect_by_listen_address(u_short listen_port)
+{
+       int i;
+
+       for (i = 0; i < num_permitted_opens; i++)
+               if (permitted_opens[i].listen_port == listen_port)
+                       return connect_to(
+                           permitted_opens[i].host_to_connect,
+                           permitted_opens[i].port_to_connect);
+       error("WARNING: Server requests forwarding for unknown listen_port %d",
+           listen_port);
+       return -1;
+}
+
+/* Check if connecting to that port is permitted and connect. */
+int
+channel_connect_to(const char *host, u_short port)
+{
+       int i, permit;
+
+       permit = all_opens_permitted;
+       if (!permit) {
+               for (i = 0; i < num_permitted_opens; i++)
+                       if (permitted_opens[i].port_to_connect == port &&
+                           strcmp(permitted_opens[i].host_to_connect, host) == 0)
+                               permit = 1;
+
+       }
+       if (!permit) {
+               log("Received request to connect to host %.100s port %d, "
+                   "but the request was denied.", host, port);
+               return -1;
+       }
+       return connect_to(host, port);
+}
+
+/* -- X11 forwarding */
+
+/*
+ * Creates an internet domain socket for listening for X11 connections.
+ * Returns a suitable value for the DISPLAY variable, or NULL if an error
+ * occurs.
+ */
+char *
+x11_create_display_inet(int screen_number, int x11_display_offset)
+{
+       int display_number, sock;
+       u_short port;
+       struct addrinfo hints, *ai, *aitop;
+       char strport[NI_MAXSERV];
+       int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
+       char display[512];
+       char hostname[MAXHOSTNAMELEN];
+
+       for (display_number = x11_display_offset;
+            display_number < MAX_DISPLAYS;
+            display_number++) {
+               port = 6000 + display_number;
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = IPv4or6;
+               hints.ai_flags = AI_PASSIVE;            /* XXX loopback only ? */
+               hints.ai_socktype = SOCK_STREAM;
+               snprintf(strport, sizeof strport, "%d", port);
+               if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
+                       error("getaddrinfo: %.100s", gai_strerror(gaierr));
+                       return NULL;
+               }
+               for (ai = aitop; ai; ai = ai->ai_next) {
+                       if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                               continue;
+                       sock = socket(ai->ai_family, SOCK_STREAM, 0);
+                       if (sock < 0) {
+                               if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) {
+                                       error("socket: %.100s", strerror(errno));
+                                       return NULL;
+                               } else {
+                                       debug("x11_create_display_inet: Socket family %d not supported",
+                                                ai->ai_family);
+                                       continue;
+                               }
+                       }
+                       if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                               debug("bind port %d: %.100s", port, strerror(errno));
+                               shutdown(sock, SHUT_RDWR);
+                               close(sock);
+
+                               if (ai->ai_next)
+                                       continue;
+
+                               for (n = 0; n < num_socks; n++) {
+                                       shutdown(socks[n], SHUT_RDWR);
+                                       close(socks[n]);
+                               }
+                               num_socks = 0;
+                               break;
+                       }
+                       socks[num_socks++] = sock;
+#ifndef DONT_TRY_OTHER_AF
+                       if (num_socks == NUM_SOCKS)
+                               break;
+#else
+                       break;
+#endif
+               }
+               freeaddrinfo(aitop);
+               if (num_socks > 0)
+                       break;
+       }
+       if (display_number >= MAX_DISPLAYS) {
+               error("Failed to allocate internet-domain X11 display socket.");
+               return NULL;
+       }
+       /* Start listening for connections on the socket. */
+       for (n = 0; n < num_socks; n++) {
+               sock = socks[n];
+               if (listen(sock, 5) < 0) {
+                       error("listen: %.100s", strerror(errno));
+                       shutdown(sock, SHUT_RDWR);
+                       close(sock);
+                       return NULL;
+               }
+       }
+
+       /* Set up a suitable value for the DISPLAY variable. */
+       if (gethostname(hostname, sizeof(hostname)) < 0)
+               fatal("gethostname: %.100s", strerror(errno));
+
+#ifdef IPADDR_IN_DISPLAY
+       /*
+        * HPUX detects the local hostname in the DISPLAY variable and tries
+        * to set up a shared memory connection to the server, which it
+        * incorrectly supposes to be local.
+        *
+        * The workaround - as used in later $$H and other programs - is
+        * is to set display to the host's IP address.
+        */
+       {
+               struct hostent *he;
+               struct in_addr my_addr;
+
+               he = gethostbyname(hostname);
+               if (he == NULL) {
+                       error("[X11-broken-fwd-hostname-workaround] Could not get "
+                               "IP address for hostname %s.", hostname);
+
+                       packet_send_debug("[X11-broken-fwd-hostname-workaround]"
+                               "Could not get IP address for hostname %s.", hostname);
+
+                       shutdown(sock, SHUT_RDWR);
+                       close(sock);
+
+                       return NULL;
+               }
+
+               memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
+
+               /* Set DISPLAY to <ip address>:screen.display */
+               snprintf(display, sizeof(display), "%.50s:%d.%d", inet_ntoa(my_addr),
+                        display_number, screen_number);
+       }
+#else /* IPADDR_IN_DISPLAY */
+       /* Just set DISPLAY to hostname:screen.display */
+       snprintf(display, sizeof display, "%.400s:%d.%d", hostname,
+                display_number, screen_number);
+#endif /* IPADDR_IN_DISPLAY */
+
+       /* Allocate a channel for each socket. */
+       for (n = 0; n < num_socks; n++) {
+               sock = socks[n];
+               (void) channel_new("x11 listener",
+                   SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
+                   CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
+                   0, xstrdup("X11 inet listener"), 1);
+       }
+
+       /* Return a suitable value for the DISPLAY environment variable. */
+       return xstrdup(display);
+}
+
+#ifndef X_UNIX_PATH
+#define X_UNIX_PATH "/tmp/.X11-unix/X"
+#endif
+
+static int
+connect_local_xsocket(u_int dnr)
+{
+       static const char *const x_sockets[] = {
+               X_UNIX_PATH "%u",
+               "/var/X/.X11-unix/X" "%u",
+               "/usr/spool/sockets/X11/" "%u",
+               NULL
+       };
+       int sock;
+       struct sockaddr_un addr;
+       const char *const * path;
+
+       for (path = x_sockets; *path; ++path) {
+               sock = socket(AF_UNIX, SOCK_STREAM, 0);
+               if (sock < 0)
+                       error("socket: %.100s", strerror(errno));
+               memset(&addr, 0, sizeof(addr));
+               addr.sun_family = AF_UNIX;
+               snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr);
+               if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0)
+                       return sock;
+               close(sock);
+       }
+       error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
+       return -1;
+}
+
+int
+x11_connect_display(void)
+{
+       int display_number, sock = 0;
+       const char *display;
+       char buf[1024], *cp;
+       struct addrinfo hints, *ai, *aitop;
+       char strport[NI_MAXSERV];
+       int gaierr;
+
+       /* Try to open a socket for the local X server. */
+       display = getenv("DISPLAY");
+       if (!display) {
+               error("DISPLAY not set.");
+               return -1;
+       }
+       /*
+        * Now we decode the value of the DISPLAY variable and make a
+        * connection to the real X server.
+        */
+
+       /*
+        * Check if it is a unix domain socket.  Unix domain displays are in
+        * one of the following formats: unix:d[.s], :d[.s], ::d[.s]
+        */
+       if (strncmp(display, "unix:", 5) == 0 ||
+           display[0] == ':') {
+               /* Connect to the unix domain socket. */
+               if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) {
+                       error("Could not parse display number from DISPLAY: %.100s",
+                             display);
+                       return -1;
+               }
+               /* Create a socket. */
+               sock = connect_local_xsocket(display_number);
+               if (sock < 0)
+                       return -1;
+
+               /* OK, we now have a connection to the display. */
+               return sock;
+       }
+       /*
+        * Connect to an inet socket.  The DISPLAY value is supposedly
+        * hostname:d[.s], where hostname may also be numeric IP address.
+        */
+       strncpy(buf, display, sizeof(buf));
+       buf[sizeof(buf) - 1] = 0;
+       cp = strchr(buf, ':');
+       if (!cp) {
+               error("Could not find ':' in DISPLAY: %.100s", display);
+               return -1;
+       }
+       *cp = 0;
+       /* buf now contains the host name.  But first we parse the display number. */
+       if (sscanf(cp + 1, "%d", &display_number) != 1) {
+               error("Could not parse display number from DISPLAY: %.100s",
+                     display);
+               return -1;
+       }
+
+       /* Look up the host address */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", 6000 + display_number);
+       if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
+               error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));
+               return -1;
+       }
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               /* Create a socket. */
+               sock = socket(ai->ai_family, SOCK_STREAM, 0);
+               if (sock < 0) {
+                       debug("socket: %.100s", strerror(errno));
+                       continue;
+               }
+               /* Connect it to the display. */
+               if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       debug("connect %.100s port %d: %.100s", buf,
+                           6000 + display_number, strerror(errno));
+                       close(sock);
+                       continue;
+               }
+               /* Success */
+               break;
+       }
+       freeaddrinfo(aitop);
+       if (!ai) {
+               error("connect %.100s port %d: %.100s", buf, 6000 + display_number,
+                   strerror(errno));
+               return -1;
+       }
+       return sock;
+}
+
+/*
+ * This is called when SSH_SMSG_X11_OPEN is received.  The packet contains
+ * the remote channel number.  We should do whatever we want, and respond
+ * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
+ */
+
+void
+x11_input_open(int type, int plen, void *ctxt)
+{
+       Channel *c = NULL;
+       int remote_id, sock = 0;
+       char *remote_host;
+
+       debug("Received X11 open request.");
+
+       remote_id = packet_get_int();
+
+       if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
+               remote_host = packet_get_string(NULL);
+       } else {
+               remote_host = xstrdup("unknown (remote did not supply name)");
+       }
+       packet_done();
+
+       /* Obtain a connection to the real X display. */
+       sock = x11_connect_display();
+       if (sock != -1) {
+               /* Allocate a channel for this connection. */
+               c = channel_new("connected x11 socket",
+                   SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0,
+                   remote_host, 1);
+               if (c == NULL) {
+                       error("x11_input_open: channel_new failed");
+                       close(sock);
+               } else {
+                       c->remote_id = remote_id;
+                       c->force_drain = 1;
+               }
+       }
+       if (c == NULL) {
+               /* Send refusal to the remote host. */
+               packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+               packet_put_int(remote_id);
+       } else {
+               /* Send a confirmation to the remote host. */
+               packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+               packet_put_int(remote_id);
+               packet_put_int(c->self);
+       }
+       packet_send();
+}
+
+/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
+void
+deny_input_open(int type, int plen, void *ctxt)
+{
+       int rchan = packet_get_int();
+       switch(type){
+       case SSH_SMSG_AGENT_OPEN:
+               error("Warning: ssh server tried agent forwarding.");
+               break;
+       case SSH_SMSG_X11_OPEN:
+               error("Warning: ssh server tried X11 forwarding.");
+               break;
+       default:
+               error("deny_input_open: type %d plen %d", type, plen);
+               break;
+       }
+       error("Warning: this is probably a break in attempt by a malicious server.");
+       packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+       packet_put_int(rchan);
+       packet_send();
+}
+
+/*
+ * Requests forwarding of X11 connections, generates fake authentication
+ * data, and enables authentication spoofing.
+ * This should be called in the client only.
+ */
+void
+x11_request_forwarding_with_spoofing(int client_session_id,
+    const char *proto, const char *data)
+{
+       u_int data_len = (u_int) strlen(data) / 2;
+       u_int i, value, len;
+       char *new_data;
+       int screen_number;
+       const char *cp;
+       u_int32_t rand = 0;
+
+       cp = getenv("DISPLAY");
+       if (cp)
+               cp = strchr(cp, ':');
+       if (cp)
+               cp = strchr(cp, '.');
+       if (cp)
+               screen_number = atoi(cp + 1);
+       else
+               screen_number = 0;
+
+       /* Save protocol name. */
+       x11_saved_proto = xstrdup(proto);
+
+       /*
+        * Extract real authentication data and generate fake data of the
+        * same length.
+        */
+       x11_saved_data = xmalloc(data_len);
+       x11_fake_data = xmalloc(data_len);
+       for (i = 0; i < data_len; i++) {
+               if (sscanf(data + 2 * i, "%2x", &value) != 1)
+                       fatal("x11_request_forwarding: bad authentication data: %.100s", data);
+               if (i % 4 == 0)
+                       rand = arc4random();
+               x11_saved_data[i] = value;
+               x11_fake_data[i] = rand & 0xff;
+               rand >>= 8;
+       }
+       x11_saved_data_len = data_len;
+       x11_fake_data_len = data_len;
+
+       /* Convert the fake data into hex. */
+       len = 2 * data_len + 1;
+       new_data = xmalloc(len);
+       for (i = 0; i < data_len; i++)
+               snprintf(new_data + 2 * i, len - 2 * i,
+                   "%02x", (u_char) x11_fake_data[i]);
+
+       /* Send the request packet. */
+       if (compat20) {
+               channel_request_start(client_session_id, "x11-req", 0);
+               packet_put_char(0);     /* XXX bool single connection */
+       } else {
+               packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
+       }
+       packet_put_cstring(proto);
+       packet_put_cstring(new_data);
+       packet_put_int(screen_number);
+       packet_send();
+       packet_write_wait();
+       xfree(new_data);
+}
+
+
+/* -- agent forwarding */
+
+/* Sends a message to the server to request authentication fd forwarding. */
+
+void
+auth_request_forwarding()
+{
+       packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
+       packet_send();
+       packet_write_wait();
+}
+
+/*
+ * Returns the name of the forwarded authentication socket.  Returns NULL if
+ * there is no forwarded authentication socket.  The returned value points to
+ * a static buffer.
+ */
+
+char *
+auth_get_socket_name()
+{
+       return auth_sock_name;
+}
+
+/* removes the agent forwarding socket */
+
+void
+auth_sock_cleanup_proc(void *_pw)
+{
+       struct passwd *pw = _pw;
+
+       if (auth_sock_name) {
+               temporarily_use_uid(pw);
+               unlink(auth_sock_name);
+               rmdir(auth_sock_dir);
+               auth_sock_name = NULL;
+               restore_uid();
+       }
+}
+
+/*
+ * This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
+ * This starts forwarding authentication requests.
+ */
+
+int
+auth_input_request_forwarding(struct passwd * pw)
+{
+       Channel *nc;
+       int sock;
+       struct sockaddr_un sunaddr;
+
+       if (auth_get_socket_name() != NULL) {
+               error("authentication forwarding requested twice.");
+               return 0;
+       }
+
+       /* Temporarily drop privileged uid for mkdir/bind. */
+       temporarily_use_uid(pw);
+
+       /* Allocate a buffer for the socket name, and format the name. */
+       auth_sock_name = xmalloc(MAXPATHLEN);
+       auth_sock_dir = xmalloc(MAXPATHLEN);
+       strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
+
+       /* Create private directory for socket */
+       if (mkdtemp(auth_sock_dir) == NULL) {
+               packet_send_debug("Agent forwarding disabled: "
+                   "mkdtemp() failed: %.100s", strerror(errno));
+               restore_uid();
+               xfree(auth_sock_name);
+               xfree(auth_sock_dir);
+               auth_sock_name = NULL;
+               auth_sock_dir = NULL;
+               return 0;
+       }
+       snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%d",
+                auth_sock_dir, (int) getpid());
+
+       /* delete agent socket on fatal() */
+       fatal_add_cleanup(auth_sock_cleanup_proc, pw);
+
+       /* Create the socket. */
+       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0)
+               packet_disconnect("socket: %.100s", strerror(errno));
+
+       /* Bind it to the name. */
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       strncpy(sunaddr.sun_path, auth_sock_name,
+               sizeof(sunaddr.sun_path));
+
+       if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
+               packet_disconnect("bind: %.100s", strerror(errno));
+
+       /* Restore the privileged uid. */
+       restore_uid();
+
+       /* Start listening on the socket. */
+       if (listen(sock, 5) < 0)
+               packet_disconnect("listen: %.100s", strerror(errno));
+
+       /* Allocate a channel for the authentication agent socket. */
+       nc = channel_new("auth socket",
+           SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
+           CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
+           0, xstrdup("auth socket"), 1);
+       if (nc == NULL) {
+               error("auth_input_request_forwarding: channel_new failed");
+               auth_sock_cleanup_proc(pw);
+               fatal_remove_cleanup(auth_sock_cleanup_proc, pw);
+               close(sock);
+               return 0;
+       }
+       strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
+       return 1;
+}
+
+/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
+
+void
+auth_input_open_request(int type, int plen, void *ctxt)
+{
+       Channel *c = NULL;
+       int remote_id, sock;
+       char *name;
+
+       packet_integrity_check(plen, 4, type);
+
+       /* Read the remote channel number from the message. */
+       remote_id = packet_get_int();
+
+       /*
+        * Get a connection to the local authentication agent (this may again
+        * get forwarded).
+        */
+       sock = ssh_get_authentication_socket();
+
+       /*
+        * If we could not connect the agent, send an error message back to
+        * the server. This should never happen unless the agent dies,
+        * because authentication forwarding is only enabled if we have an
+        * agent.
+        */
+       if (sock >= 0) {
+               name = xstrdup("authentication agent connection");
+               c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
+                   -1, 0, 0, 0, name, 1);
+               if (c == NULL) {
+                       error("auth_input_open_request: channel_new failed");
+                       xfree(name);
+                       close(sock);
+               } else {
+                       c->remote_id = remote_id;
+                       c->force_drain = 1;
+               }
+       }
+       if (c == NULL) {
+               packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+               packet_put_int(remote_id);
+       } else {
+               /* Send a confirmation to the remote host. */
+               debug("Forwarding authentication connection.");
+               packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+               packet_put_int(remote_id);
+               packet_put_int(c->self);
+       }
+       packet_send();
+}
diff --git a/openssh/channels.h b/openssh/channels.h
new file mode 100644 (file)
index 0000000..11ebb7b
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* RCSID("$OpenBSD: channels.h,v 1.51 2001/11/07 22:53:21 markus Exp $"); */
+
+#ifndef CHANNEL_H
+#define CHANNEL_H
+
+#include "buffer.h"
+
+/* Definitions for channel types. */
+#define SSH_CHANNEL_X11_LISTENER       1       /* Listening for inet X11 conn. */
+#define SSH_CHANNEL_PORT_LISTENER      2       /* Listening on a port. */
+#define SSH_CHANNEL_OPENING            3       /* waiting for confirmation */
+#define SSH_CHANNEL_OPEN               4       /* normal open two-way channel */
+#define SSH_CHANNEL_CLOSED             5       /* waiting for close confirmation */
+#define SSH_CHANNEL_AUTH_SOCKET                6       /* authentication socket */
+#define SSH_CHANNEL_X11_OPEN           7       /* reading first X11 packet */
+#define SSH_CHANNEL_INPUT_DRAINING     8       /* sending remaining data to conn */
+#define SSH_CHANNEL_OUTPUT_DRAINING    9       /* sending remaining data to app */
+#define SSH_CHANNEL_LARVAL             10      /* larval session */
+#define SSH_CHANNEL_RPORT_LISTENER     11      /* Listening to a R-style port  */
+#define SSH_CHANNEL_CONNECTING         12
+#define SSH_CHANNEL_DYNAMIC            13
+#define SSH_CHANNEL_ZOMBIE             14      /* Almost dead. */
+#define SSH_CHANNEL_MAX_TYPE           15
+
+#define SSH_CHANNEL_PATH_LEN           256
+
+struct Channel;
+typedef struct Channel Channel;
+
+typedef void channel_callback_fn(int, void *);
+typedef int channel_filter_fn(struct Channel *, char *, int);
+
+struct Channel {
+       int     type;           /* channel type/state */
+       int     self;           /* my own channel identifier */
+       int     remote_id;      /* channel identifier for remote peer */
+       int     istate;         /* input from channel (state of receive half) */
+       int     ostate;         /* output to channel  (state of transmit half) */
+       int     flags;          /* close sent/rcvd */
+       int     rfd;            /* read fd */
+       int     wfd;            /* write fd */
+       int     efd;            /* extended fd */
+       int     sock;           /* sock fd */
+       int     isatty;         /* rfd is a tty */
+       int     force_drain;    /* force close on iEOF */
+       int     delayed;                /* fdset hack */
+       Buffer  input;          /* data read from socket, to be sent over
+                                * encrypted connection */
+       Buffer  output;         /* data received over encrypted connection for
+                                * send on socket */
+       Buffer  extended;
+       char    path[SSH_CHANNEL_PATH_LEN];
+               /* path for unix domain sockets, or host name for forwards */
+       int     listening_port; /* port being listened for forwards */
+       int     host_port;      /* remote port to connect for forwards */
+       char   *remote_name;    /* remote hostname */
+
+       int     remote_window;
+       int     remote_maxpacket;
+       int     local_window;
+       int     local_window_max;
+       int     local_consumed;
+       int     local_maxpacket;
+       int     extended_usage;
+
+       char   *ctype;          /* type */
+
+       /* callback */
+       channel_callback_fn     *cb_fn;
+       void    *cb_arg;
+       int     cb_event;
+       channel_callback_fn     *detach_user;
+
+       /* filter */
+       channel_filter_fn       *input_filter;
+};
+
+#define CHAN_EXTENDED_IGNORE           0
+#define CHAN_EXTENDED_READ             1
+#define CHAN_EXTENDED_WRITE            2
+
+/* default window/packet sizes for tcp/x11-fwd-channel */
+#define CHAN_SES_WINDOW_DEFAULT        (32*1024)
+#define CHAN_SES_PACKET_DEFAULT        (CHAN_SES_WINDOW_DEFAULT/2)
+#define CHAN_TCP_WINDOW_DEFAULT        (32*1024)
+#define CHAN_TCP_PACKET_DEFAULT        (CHAN_TCP_WINDOW_DEFAULT/2)
+#define CHAN_X11_WINDOW_DEFAULT        (4*1024)
+#define CHAN_X11_PACKET_DEFAULT        (CHAN_X11_WINDOW_DEFAULT/2)
+
+/* possible input states */
+#define CHAN_INPUT_OPEN                        0x01
+#define CHAN_INPUT_WAIT_DRAIN          0x02
+#define CHAN_INPUT_WAIT_OCLOSE         0x04
+#define CHAN_INPUT_CLOSED              0x08
+
+/* possible output states */
+#define CHAN_OUTPUT_OPEN               0x10
+#define CHAN_OUTPUT_WAIT_DRAIN         0x20
+#define CHAN_OUTPUT_WAIT_IEOF          0x40
+#define CHAN_OUTPUT_CLOSED             0x80
+
+#define CHAN_CLOSE_SENT                        0x01
+#define CHAN_CLOSE_RCVD                        0x02
+
+/* channel management */
+
+Channel        *channel_lookup(int);
+Channel *channel_new(char *, int, int, int, int, int, int, int, char *, int);
+void    channel_set_fds(int, int, int, int, int, int);
+void    channel_free(Channel *);
+void    channel_free_all(void);
+void    channel_stop_listening(void);
+
+void    channel_send_open(int);
+void    channel_request(int, char *, int);
+void    channel_request_start(int, char *, int);
+void    channel_register_callback(int, int mtype, channel_callback_fn *, void *);
+void    channel_register_cleanup(int, channel_callback_fn *);
+void    channel_register_filter(int, channel_filter_fn *);
+void    channel_cancel_cleanup(int);
+int     channel_close_fd(int *);
+
+/* protocol handler */
+
+void    channel_input_channel_request(int, int, void *);
+void    channel_input_close(int, int, void *);
+void    channel_input_close_confirmation(int, int, void *);
+void    channel_input_data(int, int, void *);
+void    channel_input_extended_data(int, int, void *);
+void    channel_input_ieof(int, int, void *);
+void    channel_input_oclose(int, int, void *);
+void    channel_input_open_confirmation(int, int, void *);
+void    channel_input_open_failure(int, int, void *);
+void    channel_input_port_open(int, int, void *);
+void    channel_input_window_adjust(int, int, void *);
+
+/* file descriptor handling (read/write) */
+
+void    channel_prepare_select(fd_set **, fd_set **, int *, int*, int);
+void     channel_after_select(fd_set *, fd_set *);
+void     channel_output_poll(void);
+
+int      channel_not_very_much_buffered_data(void);
+void     channel_close_all(void);
+int      channel_still_open(void);
+char   *channel_open_message(void);
+int     channel_find_open(void);
+
+/* tcp forwarding */
+void    channel_set_af(int af);
+void     channel_permit_all_opens(void);
+void    channel_add_permitted_opens(char *, int);
+void    channel_clear_permitted_opens(void);
+void     channel_input_port_forward_request(int, int);
+int     channel_connect_to(const char *, u_short);
+int     channel_connect_by_listen_address(u_short);
+void    channel_request_remote_forwarding(u_short, const char *, u_short);
+int     channel_request_local_forwarding(u_short, const char *, u_short, int);
+int
+channel_request_forwarding(const char *, u_short, const char *, u_short, int,
+    int);
+
+/* x11 forwarding */
+
+int     x11_connect_display(void);
+char   *x11_create_display(int);
+char   *x11_create_display_inet(int, int);
+void     x11_input_open(int, int, void *);
+void     x11_request_forwarding(void);
+void    x11_request_forwarding_with_spoofing(int, const char *, const char *);
+void    deny_input_open(int, int, void *);
+
+/* agent forwarding */
+
+void    auth_request_forwarding(void);
+char   *auth_get_socket_name(void);
+void    auth_sock_cleanup_proc(void *);
+int     auth_input_request_forwarding(struct passwd *);
+void    auth_input_open_request(int, int, void *);
+
+/* channel close */
+
+int     chan_is_dead(Channel *, int);
+void    chan_mark_dead(Channel *);
+void    chan_init_iostates(Channel *);
+void    chan_init(void);
+
+typedef void    chan_event_fn(Channel *);
+
+/* for the input state */
+extern chan_event_fn   *chan_rcvd_oclose;
+extern chan_event_fn   *chan_read_failed;
+extern chan_event_fn   *chan_ibuf_empty;
+
+/* for the output state */
+extern chan_event_fn   *chan_rcvd_ieof;
+extern chan_event_fn   *chan_write_failed;
+extern chan_event_fn   *chan_obuf_empty;
+
+#endif
diff --git a/openssh/cipher.c b/openssh/cipher.c
new file mode 100644 (file)
index 0000000..de25ff0
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * Copyright (c) 1999 Niels Provos.  All rights reserved.
+ * Copyright (c) 1999, 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: cipher.c,v 1.47 2001/08/23 11:31:59 markus Exp $");
+
+#include "xmalloc.h"
+#include "log.h"
+#include "cipher.h"
+
+#include <openssl/md5.h>
+
+/* no encryption */
+static void
+none_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+}
+static void
+none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
+{
+}
+static void
+none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       memcpy(dest, src, len);
+}
+
+/* DES */
+static void
+des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       static int dowarn = 1;
+       if (dowarn) {
+               error("Warning: use of DES is strongly discouraged "
+                   "due to cryptographic weaknesses");
+               dowarn = 0;
+       }
+       des_set_key((void *)key, cc->u.des.key);
+}
+static void
+des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
+{
+       memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv));
+}
+static void
+des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
+           DES_ENCRYPT);
+}
+static void
+des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
+           DES_DECRYPT);
+}
+
+/* 3DES */
+static void
+des3_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       des_set_key((void *) key, cc->u.des3.key1);
+       des_set_key((void *) (key+8), cc->u.des3.key2);
+       des_set_key((void *) (key+16), cc->u.des3.key3);
+}
+static void
+des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
+{
+       memset(cc->u.des3.iv1, 0, sizeof(cc->u.des3.iv1));
+       memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2));
+       memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3));
+       if (iv == NULL)
+               return;
+       memcpy(cc->u.des3.iv3, (char *)iv, 8);
+}
+static void
+des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       des_ede3_cbc_encrypt(src, dest, len,
+           cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
+           &cc->u.des3.iv3, DES_ENCRYPT);
+}
+static void
+des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       des_ede3_cbc_encrypt(src, dest, len,
+           cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
+           &cc->u.des3.iv3, DES_DECRYPT);
+}
+
+/*
+ * This is used by SSH1:
+ *
+ * What kind of triple DES are these 2 routines?
+ *
+ * Why is there a redundant initialization vector?
+ *
+ * If only iv3 was used, then, this would till effect have been
+ * outer-cbc. However, there is also a private iv1 == iv2 which
+ * perhaps makes differential analysis easier. On the other hand, the
+ * private iv1 probably makes the CRC-32 attack ineffective. This is a
+ * result of that there is no longer any known iv1 to use when
+ * choosing the X block.
+ */
+static void
+des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       des_set_key((void *) key, cc->u.des3.key1);
+       des_set_key((void *) (key+8), cc->u.des3.key2);
+       if (keylen <= 16)
+               des_set_key((void *) key, cc->u.des3.key3);
+       else
+               des_set_key((void *) (key+16), cc->u.des3.key3);
+}
+static void
+des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
+    u_int len)
+{
+       des_ncbc_encrypt(src,  dest, len, cc->u.des3.key1, &cc->u.des3.iv1,
+           DES_ENCRYPT);
+       des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, &cc->u.des3.iv2,
+           DES_DECRYPT);
+       des_ncbc_encrypt(dest, dest, len, cc->u.des3.key3, &cc->u.des3.iv3,
+           DES_ENCRYPT);
+}
+static void
+des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
+    u_int len)
+{
+       des_ncbc_encrypt(src,  dest, len, cc->u.des3.key3, &cc->u.des3.iv3,
+           DES_DECRYPT);
+       des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, &cc->u.des3.iv2,
+           DES_ENCRYPT);
+       des_ncbc_encrypt(dest, dest, len, cc->u.des3.key1, &cc->u.des3.iv1,
+           DES_DECRYPT);
+}
+
+/* Blowfish */
+static void
+blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);
+}
+static void
+blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
+{
+       if (iv == NULL)
+               memset(cc->u.bf.iv, 0, 8);
+       else
+               memcpy(cc->u.bf.iv, (char *)iv, 8);
+}
+static void
+blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
+     u_int len)
+{
+       BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
+           BF_ENCRYPT);
+}
+static void
+blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
+     u_int len)
+{
+       BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
+           BF_DECRYPT);
+}
+
+/*
+ * SSH1 uses a variation on Blowfish, all bytes must be swapped before
+ * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
+ */
+static void
+swap_bytes(const u_char *src, u_char *dst, int n)
+{
+       char c[4];
+
+       /* Process 4 bytes every lap. */
+       for (n = n / 4; n > 0; n--) {
+               c[3] = *src++;
+               c[2] = *src++;
+               c[1] = *src++;
+               c[0] = *src++;
+
+               *dst++ = c[0];
+               *dst++ = c[1];
+               *dst++ = c[2];
+               *dst++ = c[3];
+       }
+}
+
+static void
+blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
+    u_int len)
+{
+       swap_bytes(src, dest, len);
+       BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
+           BF_ENCRYPT);
+       swap_bytes(dest, dest, len);
+}
+static void
+blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
+    u_int len)
+{
+       swap_bytes(src, dest, len);
+       BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
+           BF_DECRYPT);
+       swap_bytes(dest, dest, len);
+}
+
+/* alleged rc4 */
+static void
+arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       RC4_set_key(&cc->u.rc4, keylen, (u_char *)key);
+}
+static void
+arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       RC4(&cc->u.rc4, len, (u_char *)src, dest);
+}
+
+/* CAST */
+static void
+cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       CAST_set_key(&cc->u.cast.key, keylen, (u_char *) key);
+}
+static void
+cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
+{
+       if (iv == NULL)
+               fatal("no IV for %s.", cc->cipher->name);
+       memcpy(cc->u.cast.iv, (char *)iv, 8);
+}
+static void
+cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
+           CAST_ENCRYPT);
+}
+static void
+cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
+           CAST_DECRYPT);
+}
+
+/* RIJNDAEL */
+
+#define RIJNDAEL_BLOCKSIZE 16
+static void
+rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
+{
+       rijndael_set_key(&cc->u.rijndael.enc, (char *)key, 8*keylen, 1);
+       rijndael_set_key(&cc->u.rijndael.dec, (char *)key, 8*keylen, 0);
+}
+static void
+rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
+{
+       if (iv == NULL || ivlen != RIJNDAEL_BLOCKSIZE) 
+               fatal("bad/no IV for %s.", cc->cipher->name);
+       memcpy(cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
+}
+static void
+rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
+    u_int len)
+{
+       rijndael_ctx *ctx = &cc->u.rijndael.enc;
+       u_char *iv = cc->u.rijndael.iv;
+       u_char in[RIJNDAEL_BLOCKSIZE];
+       u_char *cprev, *cnow, *plain;
+       int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;
+
+       if (len == 0)
+               return;
+       if (len % RIJNDAEL_BLOCKSIZE)
+               fatal("rijndael_cbc_encrypt: bad len %d", len);
+       cnow  = dest;
+       plain = (u_char *) src;
+       cprev = iv;
+       for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE,
+           cnow+=RIJNDAEL_BLOCKSIZE) {
+               for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
+                       in[j] = plain[j] ^ cprev[j];
+               rijndael_encrypt(ctx, in, cnow);
+               cprev = cnow;
+       }
+       memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE);
+}
+static void
+rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
+    u_int len)
+{
+       rijndael_ctx *ctx = &cc->u.rijndael.dec;
+       u_char *iv = cc->u.rijndael.iv;
+       u_char ivsaved[RIJNDAEL_BLOCKSIZE];
+       u_char *cnow  = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE);
+       u_char *plain = dest+len-RIJNDAEL_BLOCKSIZE;
+       u_char *ivp;
+       int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;
+
+       if (len == 0)
+               return;
+       if (len % RIJNDAEL_BLOCKSIZE)
+               fatal("rijndael_cbc_decrypt: bad len %d", len);
+       memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE);
+       for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE,
+           plain-=RIJNDAEL_BLOCKSIZE) {
+               rijndael_decrypt(ctx, cnow, plain);
+               ivp = (i == 1) ? iv : cnow-RIJNDAEL_BLOCKSIZE;
+               for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
+                       plain[j] ^= ivp[j];
+       }
+       memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE);
+}
+
+Cipher ciphers[] = {
+       { "none",
+               SSH_CIPHER_NONE, 8, 0,
+               none_setkey, none_setiv,
+               none_crypt, none_crypt },
+       { "des",
+               SSH_CIPHER_DES, 8, 8,
+               des_ssh1_setkey, des_ssh1_setiv,
+               des_ssh1_encrypt, des_ssh1_decrypt },
+       { "3des",
+               SSH_CIPHER_3DES, 8, 16,
+               des3_ssh1_setkey, des3_setiv,
+               des3_ssh1_encrypt, des3_ssh1_decrypt },
+       { "blowfish",
+               SSH_CIPHER_BLOWFISH, 8, 16,
+               blowfish_setkey, blowfish_setiv,
+               blowfish_ssh1_encrypt, blowfish_ssh1_decrypt },
+
+       { "3des-cbc",
+               SSH_CIPHER_SSH2, 8, 24,
+               des3_setkey, des3_setiv,
+               des3_cbc_encrypt, des3_cbc_decrypt },
+       { "blowfish-cbc",
+               SSH_CIPHER_SSH2, 8, 16,
+               blowfish_setkey, blowfish_setiv,
+               blowfish_cbc_encrypt, blowfish_cbc_decrypt },
+       { "cast128-cbc",
+               SSH_CIPHER_SSH2, 8, 16,
+               cast_setkey, cast_setiv,
+               cast_cbc_encrypt, cast_cbc_decrypt },
+       { "arcfour",
+               SSH_CIPHER_SSH2, 8, 16,
+               arcfour_setkey, none_setiv,
+               arcfour_crypt, arcfour_crypt },
+       { "aes128-cbc",
+               SSH_CIPHER_SSH2, 16, 16,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { "aes192-cbc",
+               SSH_CIPHER_SSH2, 16, 24,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { "aes256-cbc",
+               SSH_CIPHER_SSH2, 16, 32,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { "rijndael128-cbc",
+               SSH_CIPHER_SSH2, 16, 16,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { "rijndael192-cbc",
+               SSH_CIPHER_SSH2, 16, 24,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { "rijndael256-cbc",
+               SSH_CIPHER_SSH2, 16, 32,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { "rijndael-cbc@lysator.liu.se",
+               SSH_CIPHER_SSH2, 16, 32,
+               rijndael_setkey, rijndael_setiv,
+               rijndael_cbc_encrypt, rijndael_cbc_decrypt },
+       { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+/*--*/
+
+u_int
+cipher_mask_ssh1(int client)
+{
+       u_int mask = 0;
+       mask |= 1 << SSH_CIPHER_3DES;           /* Mandatory */
+       mask |= 1 << SSH_CIPHER_BLOWFISH;
+       if (client) {
+               mask |= 1 << SSH_CIPHER_DES;
+       }
+       return mask;
+}
+
+Cipher *
+cipher_by_name(const char *name)
+{
+       Cipher *c;
+       for (c = ciphers; c->name != NULL; c++)
+               if (strcasecmp(c->name, name) == 0)
+                       return c;
+       return NULL;
+}
+
+Cipher *
+cipher_by_number(int id)
+{
+       Cipher *c;
+       for (c = ciphers; c->name != NULL; c++)
+               if (c->number == id)
+                       return c;
+       return NULL;
+}
+
+#define        CIPHER_SEP      ","
+int
+ciphers_valid(const char *names)
+{
+       Cipher *c;
+       char *ciphers, *cp;
+       char *p;
+
+       if (names == NULL || strcmp(names, "") == 0)
+               return 0;
+       ciphers = cp = xstrdup(names);
+       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) {
+                       debug("bad cipher %s [%s]", p, names);
+                       xfree(ciphers);
+                       return 0;
+               } else {
+                       debug3("cipher ok: %s [%s]", p, names);
+               }
+       }
+       debug3("ciphers ok: [%s]", names);
+       xfree(ciphers);
+       return 1;
+}
+
+/*
+ * Parses the name of the cipher.  Returns the number of the corresponding
+ * cipher, or -1 on error.
+ */
+
+int
+cipher_number(const char *name)
+{
+       Cipher *c;
+       if (name == NULL)
+               return -1;
+       c = cipher_by_name(name);
+       return (c==NULL) ? -1 : c->number;
+}
+
+char *
+cipher_name(int id)
+{
+       Cipher *c = cipher_by_number(id);
+       return (c==NULL) ? "<unknown>" : c->name;
+}
+
+void
+cipher_init(CipherContext *cc, Cipher *cipher,
+    const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)
+{
+       if (keylen < cipher->key_len)
+               fatal("cipher_init: key length %d is insufficient for %s.",
+                   keylen, cipher->name);
+       if (iv != NULL && ivlen < cipher->block_size)
+               fatal("cipher_init: iv length %d is insufficient for %s.",
+                   ivlen, cipher->name);
+       cc->cipher = cipher;
+       cipher->setkey(cc, key, keylen);
+       cipher->setiv(cc, iv, ivlen);
+}
+
+void
+cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       if (len % cc->cipher->block_size)
+               fatal("cipher_encrypt: bad plaintext length %d", len);
+       cc->cipher->encrypt(cc, dest, src, len);
+}
+
+void
+cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+       if (len % cc->cipher->block_size)
+               fatal("cipher_decrypt: bad ciphertext length %d", len);
+       cc->cipher->decrypt(cc, dest, src, len);
+}
+
+/*
+ * Selects the cipher, and keys if by computing the MD5 checksum of the
+ * passphrase and using the resulting 16 bytes as the key.
+ */
+
+void
+cipher_set_key_string(CipherContext *cc, Cipher *cipher,
+    const char *passphrase)
+{
+       MD5_CTX md;
+       u_char digest[16];
+
+       MD5_Init(&md);
+       MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
+       MD5_Final(digest, &md);
+
+       cipher_init(cc, cipher, digest, 16, NULL, 0);
+
+       memset(digest, 0, sizeof(digest));
+       memset(&md, 0, sizeof(md));
+}
diff --git a/openssh/cipher.h b/openssh/cipher.h
new file mode 100644 (file)
index 0000000..4533f5e
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* RCSID("$OpenBSD: cipher.h,v 1.29 2001/08/23 11:31:59 markus Exp $"); */
+
+#ifndef CIPHER_H
+#define CIPHER_H
+
+#include <openssl/des.h>
+#include <openssl/blowfish.h>
+#include <openssl/rc4.h>
+#include <openssl/cast.h>
+#include "rijndael.h"
+/*
+ * Cipher types for SSH-1.  New types can be added, but old types should not
+ * be removed for compatibility.  The maximum allowed value is 31.
+ */
+#define SSH_CIPHER_SSH2                -3
+#define SSH_CIPHER_ILLEGAL     -2      /* No valid cipher selected. */
+#define SSH_CIPHER_NOT_SET     -1      /* None selected (invalid number). */
+#define SSH_CIPHER_NONE                0       /* no encryption */
+#define SSH_CIPHER_IDEA                1       /* IDEA CFB */
+#define SSH_CIPHER_DES         2       /* DES CBC */
+#define SSH_CIPHER_3DES                3       /* 3DES CBC */
+#define SSH_CIPHER_BROKEN_TSS  4       /* TRI's Simple Stream encryption CBC */
+#define SSH_CIPHER_BROKEN_RC4  5       /* Alleged RC4 */
+#define SSH_CIPHER_BLOWFISH    6
+#define SSH_CIPHER_RESERVED    7
+#define SSH_CIPHER_MAX         31
+
+typedef struct Cipher Cipher;
+typedef struct CipherContext CipherContext;
+
+struct CipherContext {
+       union {
+               struct {
+                       des_key_schedule key;
+                       des_cblock iv;
+               }       des;
+               struct {
+                       des_key_schedule key1;
+                       des_key_schedule key2;
+                       des_key_schedule key3;
+                       des_cblock iv1;
+                       des_cblock iv2;
+                       des_cblock iv3;
+               }       des3;
+               struct {
+                       struct bf_key_st key;
+                       u_char iv[8];
+               }       bf;
+               struct {
+                       CAST_KEY key;
+                       u_char iv[8];
+               } cast;
+               struct {
+                       u_char iv[16];
+                       rijndael_ctx enc;
+                       rijndael_ctx dec;
+               } rijndael;
+               RC4_KEY rc4;
+       }       u;
+       Cipher *cipher;
+};
+struct Cipher {
+       char    *name;
+       int     number;         /* for ssh1 only */
+       u_int   block_size;
+       u_int   key_len;
+       void    (*setkey)(CipherContext *, const u_char *, u_int);
+       void    (*setiv)(CipherContext *, const u_char *, u_int);
+       void    (*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
+       void    (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
+};
+
+u_int   cipher_mask_ssh1(int);
+Cipher *cipher_by_name(const char *);
+Cipher *cipher_by_number(int);
+int     cipher_number(const char *);
+char   *cipher_name(int);
+int     ciphers_valid(const char *);
+void    cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
+    const u_char *, u_int);
+void    cipher_encrypt(CipherContext *, u_char *, const u_char *, u_int);
+void    cipher_decrypt(CipherContext *, u_char *, const u_char *, u_int);
+void    cipher_set_key_string(CipherContext *, Cipher *, const char *);
+
+#endif                         /* CIPHER_H */
diff --git a/openssh/clientloop.c b/openssh/clientloop.c
new file mode 100644 (file)
index 0000000..cbcb1d1
--- /dev/null
@@ -0,0 +1,1292 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * The main loop for the interactive session (client side).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * SSH2 support added by Markus Friedl.
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: clientloop.c,v 1.87 2001/11/09 18:59:23 markus Exp $");
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "packet.h"
+#include "buffer.h"
+#include "compat.h"
+#include "channels.h"
+#include "dispatch.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "kex.h"
+#include "log.h"
+#include "readconf.h"
+#include "clientloop.h"
+#include "authfd.h"
+#include "atomicio.h"
+#include "sshtty.h"
+#include "misc.h"
+
+/* import options */
+extern Options options;
+
+/* Flag indicating that stdin should be redirected from /dev/null. */
+extern int stdin_null_flag;
+
+/*
+ * Name of the host we are connecting to.  This is the name given on the
+ * command line, or the HostName specified for the user-supplied name in a
+ * configuration file.
+ */
+extern char *host;
+
+/*
+ * Flag to indicate that we have received a window change signal which has
+ * not yet been processed.  This will cause a message indicating the new
+ * window size to be sent to the server a little later.  This is volatile
+ * because this is updated in a signal handler.
+ */
+static volatile int received_window_change_signal = 0;
+static volatile int received_signal = 0;
+
+/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
+static int in_non_blocking_mode = 0;
+
+/* Common data for the client loop code. */
+static int quit_pending;       /* Set to non-zero to quit the client loop. */
+static int escape_char;                /* Escape character. */
+static int escape_pending;     /* Last character was the escape character */
+static int last_was_cr;                /* Last character was a newline. */
+static int exit_status;                /* Used to store the exit status of the command. */
+static int stdin_eof;          /* EOF has been encountered on standard error. */
+static Buffer stdin_buffer;    /* Buffer for stdin data. */
+static Buffer stdout_buffer;   /* Buffer for stdout data. */
+static Buffer stderr_buffer;   /* Buffer for stderr data. */
+static u_long stdin_bytes, stdout_bytes, stderr_bytes;
+static u_int buffer_high;/* Soft max buffer size. */
+static int connection_in;      /* Connection to server (input). */
+static int connection_out;     /* Connection to server (output). */
+static int need_rekeying;      /* Set to non-zero if rekeying is requested. */
+static int session_closed = 0; /* In SSH2: login session closed. */
+
+static void client_init_dispatch(void);
+int    session_ident = -1;
+
+/*XXX*/
+extern Kex *xxx_kex;
+
+/* Restores stdin to blocking mode. */
+
+static void
+leave_non_blocking(void)
+{
+       if (in_non_blocking_mode) {
+               (void) fcntl(fileno(stdin), F_SETFL, 0);
+               in_non_blocking_mode = 0;
+               fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL);
+       }
+}
+
+/* Puts stdin terminal in non-blocking mode. */
+
+static void
+enter_non_blocking(void)
+{
+       in_non_blocking_mode = 1;
+       (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
+       fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
+}
+
+/*
+ * Signal handler for the window change signal (SIGWINCH).  This just sets a
+ * flag indicating that the window has changed.
+ */
+
+static void
+window_change_handler(int sig)
+{
+       received_window_change_signal = 1;
+       signal(SIGWINCH, window_change_handler);
+}
+
+/*
+ * Signal handler for signals that cause the program to terminate.  These
+ * signals must be trapped to restore terminal modes.
+ */
+
+static void
+signal_handler(int sig)
+{
+       received_signal = sig;
+       quit_pending = 1;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * This is called when the interactive is entered.  This checks if there is
+ * an EOF coming on stdin.  We must check this explicitly, as select() does
+ * not appear to wake up when redirecting from /dev/null.
+ */
+
+static void
+client_check_initial_eof_on_stdin(void)
+{
+       int len;
+       char buf[1];
+
+       /*
+        * If standard input is to be "redirected from /dev/null", we simply
+        * mark that we have seen an EOF and send an EOF message to the
+        * server. Otherwise, we try to read a single character; it appears
+        * that for some files, such /dev/null, select() never wakes up for
+        * read for this descriptor, which means that we never get EOF.  This
+        * way we will get the EOF if stdin comes from /dev/null or similar.
+        */
+       if (stdin_null_flag) {
+               /* Fake EOF on stdin. */
+               debug("Sending eof.");
+               stdin_eof = 1;
+               packet_start(SSH_CMSG_EOF);
+               packet_send();
+       } else {
+               enter_non_blocking();
+
+               /* Check for immediate EOF on stdin. */
+               len = read(fileno(stdin), buf, 1);
+               if (len == 0) {
+                       /* EOF.  Record that we have seen it and send EOF to server. */
+                       debug("Sending eof.");
+                       stdin_eof = 1;
+                       packet_start(SSH_CMSG_EOF);
+                       packet_send();
+               } else if (len > 0) {
+                       /*
+                        * Got data.  We must store the data in the buffer,
+                        * and also process it as an escape character if
+                        * appropriate.
+                        */
+                       if ((u_char) buf[0] == escape_char)
+                               escape_pending = 1;
+                       else
+                               buffer_append(&stdin_buffer, buf, 1);
+               }
+               leave_non_blocking();
+       }
+}
+
+
+/*
+ * Make packets from buffered stdin data, and buffer them for sending to the
+ * connection.
+ */
+
+static void
+client_make_packets_from_stdin_data(void)
+{
+       u_int len;
+
+       /* Send buffered stdin data to the server. */
+       while (buffer_len(&stdin_buffer) > 0 &&
+              packet_not_very_much_data_to_write()) {
+               len = buffer_len(&stdin_buffer);
+               /* Keep the packets at reasonable size. */
+               if (len > packet_get_maxsize())
+                       len = packet_get_maxsize();
+               packet_start(SSH_CMSG_STDIN_DATA);
+               packet_put_string(buffer_ptr(&stdin_buffer), len);
+               packet_send();
+               buffer_consume(&stdin_buffer, len);
+               stdin_bytes += len;
+               /* If we have a pending EOF, send it now. */
+               if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
+                       packet_start(SSH_CMSG_EOF);
+                       packet_send();
+               }
+       }
+}
+
+/*
+ * Checks if the client window has changed, and sends a packet about it to
+ * the server if so.  The actual change is detected elsewhere (by a software
+ * interrupt on Unix); this just checks the flag and sends a message if
+ * appropriate.
+ */
+
+static void
+client_check_window_change(void)
+{
+       struct winsize ws;
+
+       if (! received_window_change_signal)
+               return;
+       /** XXX race */
+       received_window_change_signal = 0;
+
+       if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
+               return;
+
+       debug2("client_check_window_change: changed");
+
+       if (compat20) {
+               channel_request_start(session_ident, "window-change", 0);
+               packet_put_int(ws.ws_col);
+               packet_put_int(ws.ws_row);
+               packet_put_int(ws.ws_xpixel);
+               packet_put_int(ws.ws_ypixel);
+               packet_send();
+       } else {
+               packet_start(SSH_CMSG_WINDOW_SIZE);
+               packet_put_int(ws.ws_row);
+               packet_put_int(ws.ws_col);
+               packet_put_int(ws.ws_xpixel);
+               packet_put_int(ws.ws_ypixel);
+               packet_send();
+       }
+}
+
+/*
+ * Waits until the client can do something (some data becomes available on
+ * one of the file descriptors).
+ */
+
+static void
+client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
+    int *maxfdp, int *nallocp, int rekeying)
+{
+       /* Add any selections by the channel mechanism. */
+       channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
+
+       if (!compat20) {
+               /* Read from the connection, unless our buffers are full. */
+               if (buffer_len(&stdout_buffer) < buffer_high &&
+                   buffer_len(&stderr_buffer) < buffer_high &&
+                   channel_not_very_much_buffered_data())
+                       FD_SET(connection_in, *readsetp);
+               /*
+                * Read from stdin, unless we have seen EOF or have very much
+                * buffered data to send to the server.
+                */
+               if (!stdin_eof && packet_not_very_much_data_to_write())
+                       FD_SET(fileno(stdin), *readsetp);
+
+               /* Select stdout/stderr if have data in buffer. */
+               if (buffer_len(&stdout_buffer) > 0)
+                       FD_SET(fileno(stdout), *writesetp);
+               if (buffer_len(&stderr_buffer) > 0)
+                       FD_SET(fileno(stderr), *writesetp);
+       } else {
+               /* channel_prepare_select could have closed the last channel */
+               if (session_closed && !channel_still_open() &&
+                   !packet_have_data_to_write()) {
+                       /* clear mask since we did not call select() */
+                       memset(*readsetp, 0, *nallocp);
+                       memset(*writesetp, 0, *nallocp);
+                       return;
+               } else {
+                       FD_SET(connection_in, *readsetp);
+               }
+       }
+
+       /* Select server connection if have data to write to the server. */
+       if (packet_have_data_to_write())
+               FD_SET(connection_out, *writesetp);
+
+       /*
+        * Wait for something to happen.  This will suspend the process until
+        * some selected descriptor can be read, written, or has some other
+        * event pending. Note: if you want to implement SSH_MSG_IGNORE
+        * messages to fool traffic analysis, this might be the place to do
+        * it: just have a random timeout for the select, and send a random
+        * SSH_MSG_IGNORE packet when the timeout expires.
+        */
+
+       if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
+               char buf[100];
+
+               /*
+                * We have to clear the select masks, because we return.
+                * We have to return, because the mainloop checks for the flags
+                * set by the signal handlers.
+                */
+               memset(*readsetp, 0, *nallocp);
+               memset(*writesetp, 0, *nallocp);
+
+               if (errno == EINTR)
+                       return;
+               /* Note: we might still have data in the buffers. */
+               snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
+               buffer_append(&stderr_buffer, buf, strlen(buf));
+               quit_pending = 1;
+       }
+}
+
+static void
+client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
+{
+       struct winsize oldws, newws;
+
+       /* Flush stdout and stderr buffers. */
+       if (buffer_len(bout) > 0)
+               atomicio(write, fileno(stdout), buffer_ptr(bout), buffer_len(bout));
+       if (buffer_len(berr) > 0)
+               atomicio(write, fileno(stderr), buffer_ptr(berr), buffer_len(berr));
+
+       leave_raw_mode();
+
+       /*
+        * Free (and clear) the buffer to reduce the amount of data that gets
+        * written to swap.
+        */
+       buffer_free(bin);
+       buffer_free(bout);
+       buffer_free(berr);
+
+       /* Save old window size. */
+       ioctl(fileno(stdin), TIOCGWINSZ, &oldws);
+
+       /* Send the suspend signal to the program itself. */
+       kill(getpid(), SIGTSTP);
+
+       /* Check if the window size has changed. */
+       if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
+           (oldws.ws_row != newws.ws_row ||
+            oldws.ws_col != newws.ws_col ||
+            oldws.ws_xpixel != newws.ws_xpixel ||
+            oldws.ws_ypixel != newws.ws_ypixel))
+               received_window_change_signal = 1;
+
+       /* OK, we have been continued by the user. Reinitialize buffers. */
+       buffer_init(bin);
+       buffer_init(bout);
+       buffer_init(berr);
+
+       enter_raw_mode();
+}
+
+static void
+client_process_net_input(fd_set * readset)
+{
+       int len;
+       char buf[8192];
+
+       /*
+        * Read input from the server, and add any such data to the buffer of
+        * the packet subsystem.
+        */
+       if (FD_ISSET(connection_in, readset)) {
+               /* Read as much as possible. */
+               len = read(connection_in, buf, sizeof(buf));
+               if (len == 0) {
+                       /* Received EOF.  The remote host has closed the connection. */
+                       snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
+                                host);
+                       buffer_append(&stderr_buffer, buf, strlen(buf));
+                       quit_pending = 1;
+                       return;
+               }
+               /*
+                * There is a kernel bug on Solaris that causes select to
+                * sometimes wake up even though there is no data available.
+                */
+               if (len < 0 && (errno == EAGAIN || errno == EINTR))
+                       len = 0;
+
+               if (len < 0) {
+                       /* An error has encountered.  Perhaps there is a network problem. */
+                       snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
+                                host, strerror(errno));
+                       buffer_append(&stderr_buffer, buf, strlen(buf));
+                       quit_pending = 1;
+                       return;
+               }
+               packet_process_incoming(buf, len);
+       }
+}
+
+/* process the characters one by one */
+static int
+process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
+{
+       char string[1024];
+       pid_t pid;
+       int bytes = 0;
+       u_int i;
+       u_char ch;
+       char *s;
+
+       for (i = 0; i < len; i++) {
+               /* Get one character at a time. */
+               ch = buf[i];
+
+               if (escape_pending) {
+                       /* We have previously seen an escape character. */
+                       /* Clear the flag now. */
+                       escape_pending = 0;
+
+                       /* Process the escaped character. */
+                       switch (ch) {
+                       case '.':
+                               /* Terminate the connection. */
+                               snprintf(string, sizeof string, "%c.\r\n", escape_char);
+                               buffer_append(berr, string, strlen(string));
+
+                               quit_pending = 1;
+                               return -1;
+
+                       case 'Z' - 64:
+                               /* Suspend the program. */
+                               /* Print a message to that effect to the user. */
+                               snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
+                               buffer_append(berr, string, strlen(string));
+
+                               /* Restore terminal modes and suspend. */
+                               client_suspend_self(bin, bout, berr);
+
+                               /* We have been continued. */
+                               continue;
+
+                       case 'R':
+                               if (compat20) {
+                                       if (datafellows & SSH_BUG_NOREKEY)
+                                               log("Server does not support re-keying");
+                                       else
+                                               need_rekeying = 1;
+                               }
+                               continue;
+
+                       case '&':
+                               /*
+                                * Detach the program (continue to serve connections,
+                                * but put in background and no more new connections).
+                                */
+                               /* Restore tty modes. */
+                               leave_raw_mode();
+
+                               /* Stop listening for new connections. */
+                               channel_stop_listening();
+
+                               snprintf(string, sizeof string,
+                                   "%c& [backgrounded]\n", escape_char);
+                               buffer_append(berr, string, strlen(string));
+
+                               /* Fork into background. */
+                               pid = fork();
+                               if (pid < 0) {
+                                       error("fork: %.100s", strerror(errno));
+                                       continue;
+                               }
+                               if (pid != 0) { /* This is the parent. */
+                                       /* The parent just exits. */
+                                       exit(0);
+                               }
+                               /* The child continues serving connections. */
+                               if (compat20) {
+                                       buffer_append(bin, "\004", 1);
+                                       /* fake EOF on stdin */
+                                       return -1;
+                               } else if (!stdin_eof) {
+                                       /*
+                                        * Sending SSH_CMSG_EOF alone does not always appear
+                                        * to be enough.  So we try to send an EOF character
+                                        * first.
+                                        */
+                                       packet_start(SSH_CMSG_STDIN_DATA);
+                                       packet_put_string("\004", 1);
+                                       packet_send();
+                                       /* Close stdin. */
+                                       stdin_eof = 1;
+                                       if (buffer_len(bin) == 0) {
+                                               packet_start(SSH_CMSG_EOF);
+                                               packet_send();
+                                       }
+                               }
+                               continue;
+
+                       case '?':
+                               snprintf(string, sizeof string,
+"%c?\r\n\
+Supported escape sequences:\r\n\
+~.  - terminate connection\r\n\
+~R  - Request rekey (SSH protocol 2 only)\r\n\
+~^Z - suspend ssh\r\n\
+~#  - list forwarded connections\r\n\
+~&  - background ssh (when waiting for connections to terminate)\r\n\
+~?  - this message\r\n\
+~~  - send the escape character by typing it twice\r\n\
+(Note that escapes are only recognized immediately after newline.)\r\n",
+                                        escape_char);
+                               buffer_append(berr, string, strlen(string));
+                               continue;
+
+                       case '#':
+                               snprintf(string, sizeof string, "%c#\r\n", escape_char);
+                               buffer_append(berr, string, strlen(string));
+                               s = channel_open_message();
+                               buffer_append(berr, s, strlen(s));
+                               xfree(s);
+                               continue;
+
+                       default:
+                               if (ch != escape_char) {
+                                       buffer_put_char(bin, escape_char);
+                                       bytes++;
+                               }
+                               /* Escaped characters fall through here */
+                               break;
+                       }
+               } else {
+                       /*
+                        * The previous character was not an escape char. Check if this
+                        * is an escape.
+                        */
+                       if (last_was_cr && ch == escape_char) {
+                               /* It is. Set the flag and continue to next character. */
+                               escape_pending = 1;
+                               continue;
+                       }
+               }
+
+               /*
+                * Normal character.  Record whether it was a newline,
+                * and append it to the buffer.
+                */
+               last_was_cr = (ch == '\r' || ch == '\n');
+               buffer_put_char(bin, ch);
+               bytes++;
+       }
+       return bytes;
+}
+
+static void
+client_process_input(fd_set * readset)
+{
+       int len;
+       char buf[8192];
+
+       /* Read input from stdin. */
+       if (FD_ISSET(fileno(stdin), readset)) {
+               /* Read as much as possible. */
+               len = read(fileno(stdin), buf, sizeof(buf));
+               if (len < 0 && (errno == EAGAIN || errno == EINTR))
+                       return;         /* we'll try again later */
+               if (len <= 0) {
+                       /*
+                        * Received EOF or error.  They are treated
+                        * similarly, except that an error message is printed
+                        * if it was an error condition.
+                        */
+                       if (len < 0) {
+                               snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
+                               buffer_append(&stderr_buffer, buf, strlen(buf));
+                       }
+                       /* Mark that we have seen EOF. */
+                       stdin_eof = 1;
+                       /*
+                        * Send an EOF message to the server unless there is
+                        * data in the buffer.  If there is data in the
+                        * buffer, no message will be sent now.  Code
+                        * elsewhere will send the EOF when the buffer
+                        * becomes empty if stdin_eof is set.
+                        */
+                       if (buffer_len(&stdin_buffer) == 0) {
+                               packet_start(SSH_CMSG_EOF);
+                               packet_send();
+                       }
+               } else if (escape_char == SSH_ESCAPECHAR_NONE) {
+                       /*
+                        * Normal successful read, and no escape character.
+                        * Just append the data to buffer.
+                        */
+                       buffer_append(&stdin_buffer, buf, len);
+               } else {
+                       /*
+                        * Normal, successful read.  But we have an escape character
+                        * and have to process the characters one by one.
+                        */
+                       if (process_escapes(&stdin_buffer, &stdout_buffer,
+                           &stderr_buffer, buf, len) == -1)
+                               return;
+               }
+       }
+}
+
+static void
+client_process_output(fd_set * writeset)
+{
+       int len;
+       char buf[100];
+
+       /* Write buffered output to stdout. */
+       if (FD_ISSET(fileno(stdout), writeset)) {
+               /* Write as much data as possible. */
+               len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
+                   buffer_len(&stdout_buffer));
+               if (len <= 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               len = 0;
+                       else {
+                               /*
+                                * An error or EOF was encountered.  Put an
+                                * error message to stderr buffer.
+                                */
+                               snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
+                               buffer_append(&stderr_buffer, buf, strlen(buf));
+                               quit_pending = 1;
+                               return;
+                       }
+               }
+               /* Consume printed data from the buffer. */
+               buffer_consume(&stdout_buffer, len);
+               stdout_bytes += len;
+       }
+       /* Write buffered output to stderr. */
+       if (FD_ISSET(fileno(stderr), writeset)) {
+               /* Write as much data as possible. */
+               len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
+                   buffer_len(&stderr_buffer));
+               if (len <= 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               len = 0;
+                       else {
+                               /* EOF or error, but can't even print error message. */
+                               quit_pending = 1;
+                               return;
+                       }
+               }
+               /* Consume printed characters from the buffer. */
+               buffer_consume(&stderr_buffer, len);
+               stderr_bytes += len;
+       }
+}
+
+/*
+ * Get packets from the connection input buffer, and process them as long as
+ * there are packets available.
+ *
+ * Any unknown packets received during the actual
+ * session cause the session to terminate.  This is
+ * intended to make debugging easier since no
+ * confirmations are sent.  Any compatible protocol
+ * extensions must be negotiated during the
+ * preparatory phase.
+ */
+
+static void
+client_process_buffered_input_packets(void)
+{
+       dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);
+}
+
+/* scan buf[] for '~' before sending data to the peer */
+
+static int
+simple_escape_filter(Channel *c, char *buf, int len)
+{
+       /* XXX we assume c->extended is writeable */
+       return process_escapes(&c->input, &c->output, &c->extended, buf, len);
+}
+
+static void
+client_channel_closed(int id, void *arg)
+{
+       if (id != session_ident)
+               error("client_channel_closed: id %d != session_ident %d",
+                   id, session_ident);
+       channel_cancel_cleanup(id);
+       session_closed = 1;
+       if (in_raw_mode())
+               leave_raw_mode();
+}
+
+/*
+ * Implements the interactive session with the server.  This is called after
+ * the user has been authenticated, and a command has been started on the
+ * remote host.  If escape_char != SSH_ESCAPECHAR_NONE, it is the character
+ * used as an escape character for terminating or suspending the session.
+ */
+
+int
+client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
+{
+       fd_set *readset = NULL, *writeset = NULL;
+       double start_time, total_time;
+       int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;
+       char buf[100];
+
+       debug("Entering interactive session.");
+
+       start_time = get_current_time();
+
+       /* Initialize variables. */
+       escape_pending = 0;
+       last_was_cr = 1;
+       exit_status = -1;
+       stdin_eof = 0;
+       buffer_high = 64 * 1024;
+       connection_in = packet_get_connection_in();
+       connection_out = packet_get_connection_out();
+       max_fd = MAX(connection_in, connection_out);
+
+       if (!compat20) {
+               /* enable nonblocking unless tty */
+               if (!isatty(fileno(stdin)))
+                       set_nonblock(fileno(stdin));
+               if (!isatty(fileno(stdout)))
+                       set_nonblock(fileno(stdout));
+               if (!isatty(fileno(stderr)))
+                       set_nonblock(fileno(stderr));
+               max_fd = MAX(max_fd, fileno(stdin));
+               max_fd = MAX(max_fd, fileno(stdout));
+               max_fd = MAX(max_fd, fileno(stderr));
+       }
+       stdin_bytes = 0;
+       stdout_bytes = 0;
+       stderr_bytes = 0;
+       quit_pending = 0;
+       escape_char = escape_char_arg;
+
+       /* Initialize buffers. */
+       buffer_init(&stdin_buffer);
+       buffer_init(&stdout_buffer);
+       buffer_init(&stderr_buffer);
+
+       client_init_dispatch();
+
+       /* Set signal handlers to restore non-blocking mode.  */
+       signal(SIGINT, signal_handler);
+       signal(SIGQUIT, signal_handler);
+       signal(SIGTERM, signal_handler);
+       if (have_pty)
+               signal(SIGWINCH, window_change_handler);
+
+       if (have_pty)
+               enter_raw_mode();
+
+       if (compat20) {
+               session_ident = ssh2_chan_id;
+               if (escape_char != SSH_ESCAPECHAR_NONE)
+                       channel_register_filter(session_ident,
+                           simple_escape_filter);
+               if (session_ident != -1)
+                       channel_register_cleanup(session_ident,
+                           client_channel_closed);
+       } else {
+               /* Check if we should immediately send eof on stdin. */
+               client_check_initial_eof_on_stdin();
+       }
+
+       /* Main loop of the client for the interactive session mode. */
+       while (!quit_pending) {
+
+               /* Process buffered packets sent by the server. */
+               client_process_buffered_input_packets();
+
+               if (compat20 && session_closed && !channel_still_open())
+                       break;
+
+               rekeying = (xxx_kex != NULL && !xxx_kex->done);
+
+               if (rekeying) {
+                       debug("rekeying in progress");
+               } else {
+                       /*
+                        * Make packets of buffered stdin data, and buffer
+                        * them for sending to the server.
+                        */
+                       if (!compat20)
+                               client_make_packets_from_stdin_data();
+
+                       /*
+                        * Make packets from buffered channel data, and
+                        * enqueue them for sending to the server.
+                        */
+                       if (packet_not_very_much_data_to_write())
+                               channel_output_poll();
+
+                       /*
+                        * Check if the window size has changed, and buffer a
+                        * message about it to the server if so.
+                        */
+                       client_check_window_change();
+
+                       if (quit_pending)
+                               break;
+               }
+               /*
+                * Wait until we have something to do (something becomes
+                * available on one of the descriptors).
+                */
+               max_fd2 = max_fd;
+               client_wait_until_can_do_something(&readset, &writeset,
+                   &max_fd2, &nalloc, rekeying);
+
+               if (quit_pending)
+                       break;
+
+               /* Do channel operations unless rekeying in progress. */
+               if (!rekeying) {
+                       channel_after_select(readset, writeset);
+
+                       if (need_rekeying) {
+                               debug("user requests rekeying");
+                               xxx_kex->done = 0;
+                               kex_send_kexinit(xxx_kex);
+                               need_rekeying = 0;
+                       }
+               }
+
+               /* Buffer input from the connection.  */
+               client_process_net_input(readset);
+
+               if (quit_pending)
+                       break;
+
+               if (!compat20) {
+                       /* Buffer data from stdin */
+                       client_process_input(readset);
+                       /*
+                        * Process output to stdout and stderr.  Output to
+                        * the connection is processed elsewhere (above).
+                        */
+                       client_process_output(writeset);
+               }
+
+               /* Send as much buffered packet data as possible to the sender. */
+               if (FD_ISSET(connection_out, writeset))
+                       packet_write_poll();
+       }
+       if (readset)
+               xfree(readset);
+       if (writeset)
+               xfree(writeset);
+
+       /* Terminate the session. */
+
+       /* Stop watching for window change. */
+       if (have_pty)
+               signal(SIGWINCH, SIG_DFL);
+
+       channel_free_all();
+
+       if (have_pty)
+               leave_raw_mode();
+
+       /* restore blocking io */
+       if (!isatty(fileno(stdin)))
+               unset_nonblock(fileno(stdin));
+       if (!isatty(fileno(stdout)))
+               unset_nonblock(fileno(stdout));
+       if (!isatty(fileno(stderr)))
+               unset_nonblock(fileno(stderr));
+
+       if (received_signal) {
+               if (in_non_blocking_mode)       /* XXX */
+                       leave_non_blocking();
+               fatal("Killed by signal %d.", received_signal);
+       }
+
+       /*
+        * In interactive mode (with pseudo tty) display a message indicating
+        * that the connection has been closed.
+        */
+       if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
+               snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
+               buffer_append(&stderr_buffer, buf, strlen(buf));
+       }
+
+       /* Output any buffered data for stdout. */
+       while (buffer_len(&stdout_buffer) > 0) {
+               len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
+                   buffer_len(&stdout_buffer));
+               if (len <= 0) {
+                       error("Write failed flushing stdout buffer.");
+                       break;
+               }
+               buffer_consume(&stdout_buffer, len);
+               stdout_bytes += len;
+       }
+
+       /* Output any buffered data for stderr. */
+       while (buffer_len(&stderr_buffer) > 0) {
+               len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
+                   buffer_len(&stderr_buffer));
+               if (len <= 0) {
+                       error("Write failed flushing stderr buffer.");
+                       break;
+               }
+               buffer_consume(&stderr_buffer, len);
+               stderr_bytes += len;
+       }
+
+       /* Clear and free any buffers. */
+       memset(buf, 0, sizeof(buf));
+       buffer_free(&stdin_buffer);
+       buffer_free(&stdout_buffer);
+       buffer_free(&stderr_buffer);
+
+       /* Report bytes transferred, and transfer rates. */
+       total_time = get_current_time() - start_time;
+       debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
+             stdin_bytes, stdout_bytes, stderr_bytes, total_time);
+       if (total_time > 0)
+               debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
+                     stdin_bytes / total_time, stdout_bytes / total_time,
+                     stderr_bytes / total_time);
+
+       /* Return the exit status of the program. */
+       debug("Exit status %d", exit_status);
+       return exit_status;
+}
+
+/*********/
+
+static void
+client_input_stdout_data(int type, int plen, void *ctxt)
+{
+       u_int data_len;
+       char *data = packet_get_string(&data_len);
+       packet_integrity_check(plen, 4 + data_len, type);
+       buffer_append(&stdout_buffer, data, data_len);
+       memset(data, 0, data_len);
+       xfree(data);
+}
+static void
+client_input_stderr_data(int type, int plen, void *ctxt)
+{
+       u_int data_len;
+       char *data = packet_get_string(&data_len);
+       packet_integrity_check(plen, 4 + data_len, type);
+       buffer_append(&stderr_buffer, data, data_len);
+       memset(data, 0, data_len);
+       xfree(data);
+}
+static void
+client_input_exit_status(int type, int plen, void *ctxt)
+{
+       packet_integrity_check(plen, 4, type);
+       exit_status = packet_get_int();
+       /* Acknowledge the exit. */
+       packet_start(SSH_CMSG_EXIT_CONFIRMATION);
+       packet_send();
+       /*
+        * Must wait for packet to be sent since we are
+        * exiting the loop.
+        */
+       packet_write_wait();
+       /* Flag that we want to exit. */
+       quit_pending = 1;
+}
+
+static Channel *
+client_request_forwarded_tcpip(const char *request_type, int rchan)
+{
+       Channel* c = NULL;
+       char *listen_address, *originator_address;
+       int listen_port, originator_port;
+       int sock;
+
+       /* Get rest of the packet */
+       listen_address = packet_get_string(NULL);
+       listen_port = packet_get_int();
+       originator_address = packet_get_string(NULL);
+       originator_port = packet_get_int();
+       packet_done();
+
+       debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d",
+           listen_address, listen_port, originator_address, originator_port);
+
+       sock = channel_connect_by_listen_address(listen_port);
+       if (sock < 0) {
+               xfree(originator_address);
+               xfree(listen_address);
+               return NULL;
+       }
+       c = channel_new("forwarded-tcpip",
+           SSH_CHANNEL_CONNECTING, sock, sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
+           xstrdup(originator_address), 1);
+       if (c == NULL) {
+               error("client_request_forwarded_tcpip: channel_new failed");
+               close(sock);
+       }
+       xfree(originator_address);
+       xfree(listen_address);
+       return c;
+}
+
+static Channel*
+client_request_x11(const char *request_type, int rchan)
+{
+       Channel *c = NULL;
+       char *originator;
+       int originator_port;
+       int sock;
+
+       if (!options.forward_x11) {
+               error("Warning: ssh server tried X11 forwarding.");
+               error("Warning: this is probably a break in attempt by a malicious server.");
+               return NULL;
+       }
+       originator = packet_get_string(NULL);
+       if (datafellows & SSH_BUG_X11FWD) {
+               debug2("buggy server: x11 request w/o originator_port");
+               originator_port = 0;
+       } else {
+               originator_port = packet_get_int();
+       }
+       packet_done();
+       /* XXX check permission */
+       debug("client_request_x11: request from %s %d", originator,
+           originator_port);
+       xfree(originator);
+       sock = x11_connect_display();
+       if (sock < 0)
+               return NULL;
+       c = channel_new("x11",
+           SSH_CHANNEL_X11_OPEN, sock, sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0,
+           xstrdup("x11"), 1);
+       if (c == NULL) {
+               error("client_request_x11: channel_new failed");
+               close(sock);
+       }
+       c->force_drain = 1;
+       return c;
+}
+
+static Channel*
+client_request_agent(const char *request_type, int rchan)
+{
+       Channel *c = NULL;
+       int sock;
+
+       if (!options.forward_agent) {
+               error("Warning: ssh server tried agent forwarding.");
+               error("Warning: this is probably a break in attempt by a malicious server.");
+               return NULL;
+       }
+       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_WINDOW_DEFAULT, 0,
+           xstrdup("authentication agent connection"), 1);
+       if (c == NULL) {
+               error("client_request_agent: channel_new failed");
+               close(sock);
+       }
+       c->force_drain = 1;
+       return c;
+}
+
+/* XXXX move to generic input handler */
+static void
+client_input_channel_open(int type, int plen, void *ctxt)
+{
+       Channel *c = NULL;
+       char *ctype;
+       u_int len;
+       int rchan;
+       int rmaxpack;
+       int rwindow;
+
+       ctype = packet_get_string(&len);
+       rchan = packet_get_int();
+       rwindow = packet_get_int();
+       rmaxpack = packet_get_int();
+
+       debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
+           ctype, rchan, rwindow, rmaxpack);
+
+       if (strcmp(ctype, "forwarded-tcpip") == 0) {
+               c = client_request_forwarded_tcpip(ctype, rchan);
+       } else if (strcmp(ctype, "x11") == 0) {
+               c = client_request_x11(ctype, rchan);
+       } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
+               c = client_request_agent(ctype, rchan);
+       }
+/* XXX duplicate : */
+       if (c != NULL) {
+               debug("confirm %s", ctype);
+               c->remote_id = rchan;
+               c->remote_window = rwindow;
+               c->remote_maxpacket = rmaxpack;
+               if (c->type != SSH_CHANNEL_CONNECTING) {
+                       packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+                       packet_put_int(c->remote_id);
+                       packet_put_int(c->self);
+                       packet_put_int(c->local_window);
+                       packet_put_int(c->local_maxpacket);
+                       packet_send();
+               }
+       } else {
+               debug("failure %s", ctype);
+               packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+               packet_put_int(rchan);
+               packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
+               if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+                       packet_put_cstring("open failed");
+                       packet_put_cstring("");
+               }
+               packet_send();
+       }
+       xfree(ctype);
+}
+static void
+client_input_channel_req(int type, int plen, void *ctxt)
+{
+       Channel *c = NULL;
+       int id, reply, success = 0;
+       char *rtype;
+
+       id = packet_get_int();
+       rtype = packet_get_string(NULL);
+       reply = packet_get_char();
+
+       debug("client_input_channel_req: channel %d rtype %s reply %d",
+           id, rtype, reply);
+
+       if (session_ident == -1) {
+               error("client_input_channel_req: no channel %d", session_ident);
+       } else if (id != session_ident) {
+               error("client_input_channel_req: channel %d: wrong channel: %d",
+                   session_ident, id);
+       }
+       c = channel_lookup(id);
+       if (c == NULL) {
+               error("client_input_channel_req: channel %d: unknown channel", id);
+       } else if (strcmp(rtype, "exit-status") == 0) {
+               success = 1;
+               exit_status = packet_get_int();
+               packet_done();
+       }
+       if (reply) {
+               packet_start(success ?
+                   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+               packet_put_int(c->remote_id);
+               packet_send();
+       }
+       xfree(rtype);
+}
+
+static void
+client_init_dispatch_20(void)
+{
+       dispatch_init(&dispatch_protocol_error);
+       dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
+       dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
+       dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
+       dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
+       dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open);
+       dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
+       dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
+       dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
+       dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+
+       /* rekeying */
+       dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
+}
+static void
+client_init_dispatch_13(void)
+{
+       dispatch_init(NULL);
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
+       dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
+       dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
+       dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
+       dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
+       dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
+       dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
+       dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
+
+       dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ?
+           &auth_input_open_request : &deny_input_open);
+       dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
+           &x11_input_open : &deny_input_open);
+}
+static void
+client_init_dispatch_15(void)
+{
+       client_init_dispatch_13();
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
+}
+static void
+client_init_dispatch(void)
+{
+       if (compat20)
+               client_init_dispatch_20();
+       else if (compat13)
+               client_init_dispatch_13();
+       else
+               client_init_dispatch_15();
+}
diff --git a/openssh/clientloop.h b/openssh/clientloop.h
new file mode 100644 (file)
index 0000000..1bc9a95
--- /dev/null
@@ -0,0 +1,39 @@
+/*     $OpenBSD: clientloop.h,v 1.6 2001/06/26 17:27:23 markus Exp $   */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Client side main loop for the interactive session. */
+int     client_loop(int, int, int);
diff --git a/openssh/compat.c b/openssh/compat.c
new file mode 100644 (file)
index 0000000..1d3e970
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: compat.c,v 1.53 2001/09/20 13:50:40 markus Exp $");
+
+#ifdef HAVE_LIBPCRE
+#  include <pcreposix.h>
+#else /* Use native regex libraries */
+#  ifdef HAVE_REGEX_H
+#    include <regex.h>
+#  else
+#    include "openbsd-compat/fake-regex.h"
+#  endif
+#endif /* HAVE_LIBPCRE */
+
+#include "packet.h"
+#include "xmalloc.h"
+#include "compat.h"
+#include "log.h"
+
+int compat13 = 0;
+int compat20 = 0;
+int datafellows = 0;
+
+void
+enable_compat20(void)
+{
+       verbose("Enabling compatibility mode for protocol 2.0");
+       compat20 = 1;
+}
+void
+enable_compat13(void)
+{
+       verbose("Enabling compatibility mode for protocol 1.3");
+       compat13 = 1;
+}
+/* datafellows bug compatibility */
+void
+compat_datafellows(const char *version)
+{
+       int i, ret;
+       char ebuf[1024];
+       regex_t reg;
+       static struct {
+               char    *pat;
+               int     bugs;
+       } check[] = {
+               { "^OpenSSH[-_]2\\.[012]",
+                                       SSH_OLD_SESSIONID|SSH_BUG_BANNER|
+                                       SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
+               { "^OpenSSH_2\\.3\\.0", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
+                                       SSH_OLD_DHGEX|SSH_BUG_NOREKEY},
+               { "^OpenSSH_2\\.3\\.",  SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
+                                       SSH_BUG_NOREKEY},
+               { "^OpenSSH_2\\.5\\.[01]p1",
+                                       SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
+                                       SSH_BUG_NOREKEY },
+               { "^OpenSSH_2\\.5\\.[012]",
+                                       SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
+               { "^OpenSSH_2\\.5\\.3",
+                                       SSH_BUG_NOREKEY },
+               { "^OpenSSH",           0 },
+               { "MindTerm",           0 },
+               { "^2\\.1\\.0",         SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
+               { "^2\\.1 ",            SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
+               { "^2\\.0\\.1[3-9]",    SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
+                                       SSH_BUG_PKOK|SSH_BUG_RSASIGMD5|
+                                       SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE|
+                                       SSH_BUG_DUMMYCHAN },
+               { "^2\\.0\\.1[1-2]",    SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
+                                       SSH_BUG_PKAUTH|SSH_BUG_PKOK|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
+                                       SSH_BUG_DUMMYCHAN },
+               { "^2\\.0\\.",          SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
+                                       SSH_BUG_PKAUTH|SSH_BUG_PKOK|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
+                                       SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN },
+               { "^2\\.[23]\\.0",      SSH_BUG_HMAC|SSH_BUG_DEBUG|
+                                       SSH_BUG_RSASIGMD5 },
+               { "^2\\.3\\.",          SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5 },
+               { "^2\\.[2-9]\\.",      SSH_BUG_DEBUG },
+               { "^3\\.0\\.",          SSH_BUG_DEBUG },
+               { "^2\\.4$",            SSH_OLD_SESSIONID },    /* Van Dyke */
+               { "^3\\.0 SecureCRT",   SSH_OLD_SESSIONID },
+               { "^1\\.7 SecureFX",    SSH_OLD_SESSIONID },
+               { "^1\\.2\\.1[89]",     SSH_BUG_IGNOREMSG },
+               { "^1\\.2\\.2[012]",    SSH_BUG_IGNOREMSG },
+               { "^1\\.3\\.2",         SSH_BUG_IGNOREMSG },    /* f-secure */
+               { "^SSH Compatible Server",                     /* Netscreen */
+                                       SSH_BUG_PASSWORDPAD },
+               { "^OSU_0",             SSH_BUG_PASSWORDPAD },
+               { "^OSU_1\\.[0-4]",     SSH_BUG_PASSWORDPAD },
+               { "^OSU_1\\.5alpha[1-3]",
+                                       SSH_BUG_PASSWORDPAD },
+               { "^SSH_Version_Mapper",
+                                       SSH_BUG_SCANNER },
+               { NULL,                 0 }
+       };
+       /* process table, return first match */
+       for (i = 0; check[i].pat; i++) {
+               ret = regcomp(&reg, check[i].pat, REG_EXTENDED|REG_NOSUB);
+               if (ret != 0) {
+                       regerror(ret, &reg, ebuf, sizeof(ebuf));
+                       ebuf[sizeof(ebuf)-1] = '\0';
+                       error("regerror: %s", ebuf);
+                       continue;
+               }
+               ret = regexec(&reg, version, 0, NULL, 0);
+               regfree(&reg);
+               if (ret == 0) {
+                       debug("match: %s pat %s", version, check[i].pat);
+                       datafellows = check[i].bugs;
+                       return;
+               }
+       }
+       debug("no match: %s", version);
+}
+
+#define        SEP     ","
+int
+proto_spec(const char *spec)
+{
+       char *s, *p, *q;
+       int ret = SSH_PROTO_UNKNOWN;
+
+       if (spec == NULL)
+               return ret;
+       q = s = xstrdup(spec);
+       for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
+               switch(atoi(p)) {
+               case 1:
+                       if (ret == SSH_PROTO_UNKNOWN)
+                               ret |= SSH_PROTO_1_PREFERRED;
+                       ret |= SSH_PROTO_1;
+                       break;
+               case 2:
+                       ret |= SSH_PROTO_2;
+                       break;
+               default:
+                       log("ignoring bad proto spec: '%s'.", p);
+                       break;
+               }
+       }
+       xfree(s);
+       return ret;
+}
+
+char *
+compat_cipher_proposal(char *cipher_prop)
+{
+       char *orig_prop, *fix_ciphers;
+       char *cp, *tmp;
+       size_t len;
+
+       if (!(datafellows & SSH_BUG_BIGENDIANAES))
+               return(cipher_prop);
+
+       len = strlen(cipher_prop) + 1;
+       fix_ciphers = xmalloc(len);
+       *fix_ciphers = '\0';
+       tmp = orig_prop = xstrdup(cipher_prop);
+       while((cp = strsep(&tmp, ",")) != NULL) {
+               if (strncmp(cp, "aes", 3) && strncmp(cp, "rijndael", 8)) {
+                       if (*fix_ciphers)
+                               strlcat(fix_ciphers, ",", len);
+                       strlcat(fix_ciphers, cp, len);
+               }
+       }
+       xfree(orig_prop);
+       debug2("Original cipher proposal: %s", cipher_prop);
+       debug2("Compat cipher proposal: %s", fix_ciphers);
+       if (!*fix_ciphers)
+               fatal("No available ciphers found.");
+
+       return(fix_ciphers);
+}
diff --git a/openssh/compat.h b/openssh/compat.h
new file mode 100644 (file)
index 0000000..b6609ef
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* RCSID("$OpenBSD: compat.h,v 1.29 2001/09/20 13:50:40 markus Exp $"); */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#define        SSH_PROTO_UNKNOWN       0x00
+#define        SSH_PROTO_1             0x01
+#define        SSH_PROTO_1_PREFERRED   0x02
+#define        SSH_PROTO_2             0x04
+
+#define SSH_BUG_SIGBLOB                0x00000001
+#define SSH_BUG_PKSERVICE      0x00000002
+#define SSH_BUG_HMAC           0x00000004
+#define SSH_BUG_X11FWD         0x00000008
+#define SSH_OLD_SESSIONID      0x00000010
+#define SSH_BUG_PKAUTH         0x00000020
+#define SSH_BUG_DEBUG          0x00000040
+#define SSH_BUG_BANNER         0x00000080
+#define SSH_BUG_IGNOREMSG      0x00000100
+#define SSH_BUG_PKOK           0x00000200
+#define SSH_BUG_PASSWORDPAD    0x00000400
+#define SSH_BUG_SCANNER                0x00000800
+#define SSH_BUG_BIGENDIANAES   0x00001000
+#define SSH_BUG_RSASIGMD5      0x00002000
+#define SSH_OLD_DHGEX          0x00004000
+#define SSH_BUG_NOREKEY                0x00008000
+#define SSH_BUG_HBSERVICE      0x00010000
+#define SSH_BUG_OPENFAILURE    0x00020000
+#define SSH_BUG_DERIVEKEY      0x00040000
+#define SSH_BUG_DUMMYCHAN      0x00100000
+
+void     enable_compat13(void);
+void     enable_compat20(void);
+void     compat_datafellows(const char *);
+int     proto_spec(const char *);
+char   *compat_cipher_proposal(char *);
+
+extern int compat13;
+extern int compat20;
+extern int datafellows;
+#endif
diff --git a/openssh/compress.c b/openssh/compress.c
new file mode 100644 (file)
index 0000000..a779af6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Interface to packet compression for ssh.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: compress.c,v 1.15 2001/09/27 11:58:16 markus Exp $");
+
+#include "log.h"
+#include "buffer.h"
+#include "zlib.h"
+#include "compress.h"
+
+static z_stream incoming_stream;
+static z_stream outgoing_stream;
+static int compress_init_send_called = 0;
+static int compress_init_recv_called = 0;
+
+/*
+ * Initializes compression; level is compression level from 1 to 9
+ * (as in gzip).
+ */
+
+void
+buffer_compress_init_send(int level)
+{
+       if (compress_init_send_called == 1)
+               deflateEnd(&outgoing_stream);
+       compress_init_send_called = 1;
+       debug("Enabling compression at level %d.", level);
+       if (level < 1 || level > 9)
+               fatal("Bad compression level %d.", level);
+       deflateInit(&outgoing_stream, level);
+}
+void
+buffer_compress_init_recv(void)
+{
+       if (compress_init_recv_called == 1)
+               inflateEnd(&incoming_stream);
+       compress_init_recv_called = 1;
+       inflateInit(&incoming_stream);
+}
+
+/* Frees any data structures allocated for compression. */
+
+void
+buffer_compress_uninit(void)
+{
+       debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
+             outgoing_stream.total_in, outgoing_stream.total_out,
+             outgoing_stream.total_in == 0 ? 0.0 :
+             (double) outgoing_stream.total_out / outgoing_stream.total_in);
+       debug("compress incoming: raw data %lu, compressed %lu, factor %.2f",
+             incoming_stream.total_out, incoming_stream.total_in,
+             incoming_stream.total_out == 0 ? 0.0 :
+             (double) incoming_stream.total_in / incoming_stream.total_out);
+       if (compress_init_recv_called == 1)
+               inflateEnd(&incoming_stream);
+       if (compress_init_send_called == 1)
+               deflateEnd(&outgoing_stream);
+}
+
+/*
+ * Compresses the contents of input_buffer into output_buffer.  All packets
+ * compressed using this function will form a single compressed data stream;
+ * however, data will be flushed at the end of every call so that each
+ * output_buffer can be decompressed independently (but in the appropriate
+ * order since they together form a single compression stream) by the
+ * receiver.  This appends the compressed data to the output buffer.
+ */
+
+void
+buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
+{
+       char buf[4096];
+       int status;
+
+       /* This case is not handled below. */
+       if (buffer_len(input_buffer) == 0)
+               return;
+
+       /* Input is the contents of the input buffer. */
+       outgoing_stream.next_in = (u_char *) buffer_ptr(input_buffer);
+       outgoing_stream.avail_in = buffer_len(input_buffer);
+
+       /* Loop compressing until deflate() returns with avail_out != 0. */
+       do {
+               /* Set up fixed-size output buffer. */
+               outgoing_stream.next_out = (u_char *)buf;
+               outgoing_stream.avail_out = sizeof(buf);
+
+               /* Compress as much data into the buffer as possible. */
+               status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
+               switch (status) {
+               case Z_OK:
+                       /* Append compressed data to output_buffer. */
+                       buffer_append(output_buffer, buf,
+                           sizeof(buf) - outgoing_stream.avail_out);
+                       break;
+               default:
+                       fatal("buffer_compress: deflate returned %d", status);
+                       /* NOTREACHED */
+               }
+       } while (outgoing_stream.avail_out == 0);
+}
+
+/*
+ * Uncompresses the contents of input_buffer into output_buffer.  All packets
+ * uncompressed using this function will form a single compressed data
+ * stream; however, data will be flushed at the end of every call so that
+ * each output_buffer.  This must be called for the same size units that the
+ * buffer_compress was called, and in the same order that buffers compressed
+ * with that.  This appends the uncompressed data to the output buffer.
+ */
+
+void
+buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
+{
+       char buf[4096];
+       int status;
+
+       incoming_stream.next_in = (u_char *) buffer_ptr(input_buffer);
+       incoming_stream.avail_in = buffer_len(input_buffer);
+
+       for (;;) {
+               /* Set up fixed-size output buffer. */
+               incoming_stream.next_out = (u_char *) buf;
+               incoming_stream.avail_out = sizeof(buf);
+
+               status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
+               switch (status) {
+               case Z_OK:
+                       buffer_append(output_buffer, buf,
+                           sizeof(buf) - incoming_stream.avail_out);
+                       break;
+               case Z_BUF_ERROR:
+                       /*
+                        * Comments in zlib.h say that we should keep calling
+                        * inflate() until we get an error.  This appears to
+                        * be the error that we get.
+                        */
+                       return;
+               default:
+                       fatal("buffer_uncompress: inflate returned %d", status);
+                       /* NOTREACHED */
+               }
+       }
+}
diff --git a/openssh/compress.h b/openssh/compress.h
new file mode 100644 (file)
index 0000000..2721d45
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Interface to packet compression for ssh.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: compress.h,v 1.10 2001/06/26 17:27:23 markus Exp $"); */
+
+#ifndef COMPRESS_H
+#define COMPRESS_H
+
+void    buffer_compress_init_send(int);
+void    buffer_compress_init_recv(void);
+void     buffer_compress_uninit(void);
+void     buffer_compress(Buffer *, Buffer *);
+void     buffer_uncompress(Buffer *, Buffer *);
+
+#endif                         /* COMPRESS_H */
diff --git a/openssh/config.guess b/openssh/config.guess
new file mode 100755 (executable)
index 0000000..ba66165
--- /dev/null
@@ -0,0 +1,1371 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2001-04-20'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int dummy(){}" > $dummy.c
+       for c in cc gcc c89 ; do
+         ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1
+         if test $? = 0 ; then
+            CC_FOR_BUILD="$c"; break
+         fi
+       done
+       rm -f $dummy.c $dummy.o $dummy.rel
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # Netbsd (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       # Determine the machine/vendor (is the vendor relevant).
+       case "${UNAME_MACHINE}" in
+           amiga) machine=m68k-unknown ;;
+           arm32) machine=arm-unknown ;;
+           atari*) machine=m68k-atari ;;
+           sun3*) machine=m68k-sun ;;
+           mac68k) machine=m68k-apple ;;
+           macppc) machine=powerpc-apple ;;
+           hp3[0-9][05]) machine=m68k-hp ;;
+           ibmrt|romp-ibm) machine=romp-ibm ;;
+           *) machine=${UNAME_MACHINE}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE}" in
+           i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+              case "${HPUX_REV}" in
+                11.[0-9][0-9])
+                  if [ -x /usr/bin/getconf ]; then
+                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                        esac ;;
+                    esac
+                  fi ;;
+              esac
+              if [ "${HP_ARCH}" = "" ]; then
+              sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+       rm -f $dummy.c $dummy
+       fi ;;
+       esac
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    hppa*:OpenBSD:*:*)
+       echo hppa-unknown-openbsd
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3D:*:*:*)
+       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux
+       exit 0 ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    mips:Linux:*:*)
+       cat >$dummy.c <<EOF
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+int main (int argc, char *argv[]) {
+#else
+int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       ;;
+    ppc:Linux:*:*)
+       # Determine Lib Version
+       cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unknown\n");
+#endif
+  return 0;
+}
+EOF
+       LIBC=""
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               ./$dummy | grep 1\.99 > /dev/null
+               if test "$?" = 0 ; then LIBC="libc1" ; fi
+       fi
+       rm -f $dummy.c $dummy
+       echo powerpc-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    alpha:Linux:*:*)
+       cat <<EOF >$dummy.s
+         .data
+         \$Lformat:
+               .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+          .text
+               .globl main
+               .align 4
+               .ent main
+           main:
+               .frame \$30,16,\$26,0
+               ldgp \$29,0(\$27)
+               .prologue 1
+               .long 0x47e03d80 # implver \$0
+               lda \$2,-1
+               .long 0x47e20c21 # amask \$2,\$1
+               lda \$16,\$Lformat
+               mov \$0,\$17
+               not \$1,\$18
+               jsr \$26,printf
+               ldgp \$29,0(\$26)
+               mov 0,\$16
+               jsr \$26,exit
+               .end main
+EOF
+       LIBC=""
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+               0-0)    UNAME_MACHINE="alpha" ;;
+               1-0)    UNAME_MACHINE="alphaev5" ;;
+               1-1)    UNAME_MACHINE="alphaev56" ;;
+               1-101)  UNAME_MACHINE="alphapca56" ;;
+               2-303)  UNAME_MACHINE="alphaev6" ;;
+               2-307)  UNAME_MACHINE="alphaev67" ;;
+               esac
+               objdump --private-headers $dummy | \
+                 grep ld.so.1 > /dev/null
+               if test "$?" = 0 ; then
+                       LIBC="libc1"
+               fi
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit 0 ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit 0 ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       ld_supported_emulations=`cd /; ld --help 2>&1 \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         i*86linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0
+               ;;
+         elf_i*86)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         i*86coff)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0
+               ;;
+       esac
+       # Either a pre-BFD a.out linker (linux-gnuoldld)
+       # or one that does not give us useful --help.
+       # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+       # If ld does not provide *any* "supported emulations:"
+       # that means it is gnuoldld.
+       test -z "$ld_supported_emulations" && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+       case "${UNAME_MACHINE}" in
+       i*86)
+         VENDOR=pc;
+         ;;
+       *)
+         VENDOR=unknown;
+         ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i*86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i*86:*:5:7*)
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+       else
+           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       if test "${UNAME_MACHINE}" = "x86pc"; then
+               UNAME_MACHINE=pc
+       fi
+       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[KW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit 0 ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit 0 ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit 0 ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/openssh/config.sub b/openssh/config.sub
new file mode 100755 (executable)
index 0000000..a06a480
--- /dev/null
@@ -0,0 +1,1362 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2001-04-20'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
+               | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
+               | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 \
+               | x86 | ppcbe | mipsbe | mipsle | shbe | shle \
+               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+               | hppa64 \
+               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+               | alphaev6[78] \
+               | we32k | ns16k | clipper | i370 | sh | sh[34] \
+               | powerpc | powerpcle \
+               | 1750a | dsp16xx | pdp10 | pdp11 \
+               | mips16 | mips64 | mipsel | mips64el \
+               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+               | mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \
+               | sparc | sparclet | sparclite | sparc64 | sparcv9 | sparcv9b \
+               | v850 | c4x \
+               | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \
+               | pj | pjl | h8500)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | w65)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       # FIXME: clean up the formatting here.
+       vax-* | tahoe-* | i*86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
+             | arm-*  | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+             | xmp-* | ymp-* \
+             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+             | hppa2.0n-* | hppa64-* \
+             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+             | alphaev6[78]-* \
+             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+             | clipper-* | orion-* \
+             | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+             | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \
+             | mips16-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* \
+             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+             | mipstx39-* | mipstx39el-* | mcore-* \
+             | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
+             | [cjt]90-* \
+             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+             | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \
+             | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [cjt]90)
+               basic_machine=${basic_machine}-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i686-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=t3e-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv9 | sparcv9b)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto*)
+               os=-nto-qnx
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       pdp10-*)
+               os=-tops20
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/openssh/configure.ac b/openssh/configure.ac
new file mode 100644 (file)
index 0000000..3cc9365
--- /dev/null
@@ -0,0 +1,2248 @@
+# $Id$
+
+AC_INIT
+AC_CONFIG_SRCDIR([ssh.c])
+
+AC_CONFIG_HEADER(config.h)
+AC_PROG_CC
+AC_CANONICAL_HOST
+AC_C_BIGENDIAN
+
+# Checks for programs.
+AC_PROG_CPP
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PATH_PROG(AR, ar)
+AC_PATH_PROGS(PERL, perl5 perl)
+AC_SUBST(PERL)
+AC_PATH_PROG(ENT, ent)
+AC_SUBST(ENT)
+AC_PATH_PROGS(FILEPRIV, filepriv, true, /sbin:/usr/sbin)
+AC_PATH_PROG(TEST_MINUS_S_SH, bash)
+AC_PATH_PROG(TEST_MINUS_S_SH, ksh)
+AC_PATH_PROG(TEST_MINUS_S_SH, sh)
+
+# System features
+AC_SYS_LARGEFILE
+
+if test -z "$AR" ; then
+       AC_MSG_ERROR([*** 'ar' missing, please install or fix your \$PATH ***])
+fi
+
+# Use LOGIN_PROGRAM from environment if possible
+if test ! -z "$LOGIN_PROGRAM" ; then
+       AC_DEFINE_UNQUOTED(LOGIN_PROGRAM_FALLBACK, "$LOGIN_PROGRAM")
+else
+       # Search for login
+       AC_PATH_PROG(LOGIN_PROGRAM_FALLBACK, login)
+       if test ! -z "$LOGIN_PROGRAM_FALLBACK" ; then
+               AC_DEFINE_UNQUOTED(LOGIN_PROGRAM_FALLBACK, "$LOGIN_PROGRAM_FALLBACK")
+       fi
+fi
+
+if test -z "$LD" ; then
+       LD=$CC
+fi
+AC_SUBST(LD)
+       
+AC_C_INLINE
+if test "$GCC" = "yes" || test "$GCC" = "egcs"; then 
+       CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wno-uninitialized"
+fi
+
+# Check for some target-specific stuff
+case "$host" in
+*-*-aix*)
+       AFS_LIBS="-lld"
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       if (test "$LD" != "gcc" && test -z "$blibpath"); then
+               blibpath="/usr/lib:/lib:/usr/local/lib"
+       fi
+       AC_CHECK_FUNC(authenticate, [AC_DEFINE(WITH_AIXAUTHENTICATE)])
+       AC_DEFINE(BROKEN_GETADDRINFO)
+       dnl AIX handles lastlog as part of its login message
+       AC_DEFINE(DISABLE_LASTLOG)
+       ;;
+*-*-cygwin*)
+       LIBS="$LIBS -lregex /usr/lib/textmode.o"
+       AC_DEFINE(HAVE_CYGWIN)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(DISABLE_SHADOW)
+       AC_DEFINE(IPV4_DEFAULT)
+       AC_DEFINE(IP_TOS_IS_BROKEN)
+       AC_DEFINE(NO_X11_UNIX_SOCKETS)
+       ;;
+*-*-dgux*)
+       AC_DEFINE(IP_TOS_IS_BROKEN)
+       ;;
+*-*-darwin*)
+       AC_DEFINE(BROKEN_GETADDRINFO)
+       ;;
+*-*-hpux10*)
+       if test -z "$GCC"; then
+               CFLAGS="$CFLAGS -Ae"
+       fi
+       CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
+       IPADDR_IN_DISPLAY=yes
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(DISABLE_SHADOW)
+       AC_DEFINE(DISABLE_UTMP)
+       AC_DEFINE(SPT_TYPE,SPT_PSTAT)
+       LIBS="$LIBS -lxnet -lsec"
+       ;;
+*-*-hpux11*)
+       CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
+       IPADDR_IN_DISPLAY=yes
+       AC_DEFINE(PAM_SUN_CODEBASE)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(DISABLE_SHADOW)
+       AC_DEFINE(DISABLE_UTMP)
+       AC_DEFINE(SPT_TYPE,SPT_PSTAT)
+       LIBS="$LIBS -lxnet -lsec"
+       ;;
+*-*-irix5*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS"
+       PATH="$PATH:/usr/etc"
+       AC_DEFINE(BROKEN_INET_NTOA)
+       ;;
+*-*-irix6*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS"
+       PATH="$PATH:/usr/etc"
+       AC_DEFINE(WITH_IRIX_ARRAY)
+       AC_DEFINE(WITH_IRIX_PROJECT)
+       AC_DEFINE(WITH_IRIX_AUDIT)
+       AC_CHECK_FUNC(jlimit_startjob, [AC_DEFINE(WITH_IRIX_JOBS)])
+       AC_DEFINE(BROKEN_INET_NTOA)
+       ;;
+*-*-linux*)
+       no_dev_ptmx=1
+       check_for_libcrypt_later=1
+       AC_DEFINE(DONT_TRY_OTHER_AF)
+       AC_DEFINE(PAM_TTY_KLUDGE)
+       inet6_default_4in6=yes
+       ;;
+mips-sony-bsd|mips-sony-newsos4)
+       AC_DEFINE(HAVE_NEWS4)
+       SONY=1
+       AC_CHECK_LIB(iberty, xatexit, AC_DEFINE(HAVE_XATEXIT),
+               AC_MSG_ERROR([*** libiberty missing - please install first or check config.log ***])
+        )
+       ;;
+*-*-netbsd*)
+       need_dash_r=1
+       ;;
+*-*-freebsd*)
+       check_for_libcrypt_later=1
+       ;;
+*-next-*)
+       conf_lastlog_location="/usr/adm/lastlog"
+       conf_utmp_location=/etc/utmp
+       conf_wtmp_location=/usr/adm/wtmp
+       MAIL=/usr/spool/mail
+       AC_DEFINE(HAVE_NEXT)
+       AC_DEFINE(BROKEN_REALPATH)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(BROKEN_SAVED_UIDS)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       CFLAGS="$CFLAGS"
+       ;;
+*-*-solaris*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib" 
+       need_dash_r=1
+       AC_DEFINE(PAM_SUN_CODEBASE)
+       AC_DEFINE(LOGIN_NEEDS_UTMPX)
+       AC_DEFINE(LOGIN_NEEDS_TERM)
+       AC_DEFINE(PAM_TTY_KLUDGE)
+       # hardwire lastlog location (can't detect it on some versions)
+       conf_lastlog_location="/var/adm/lastlog"
+       AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
+       sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
+       if test "$sol2ver" -ge 8; then
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(DISABLE_UTMP)
+               AC_DEFINE(DISABLE_WTMP)
+       else
+               AC_MSG_RESULT(no)
+       fi
+       ;;
+*-*-sunos4*)
+       CPPFLAGS="$CPPFLAGS -DSUNOS4"
+       AC_CHECK_FUNCS(getpwanam)
+       AC_DEFINE(PAM_SUN_CODEBASE)
+       AC_DEFINE(HAVE_BOGUS_SYS_QUEUE_H)
+       conf_utmp_location=/etc/utmp
+       conf_wtmp_location=/var/adm/wtmp
+       conf_lastlog_location=/var/adm/lastlog
+       AC_DEFINE(USE_PIPES)
+       ;;
+*-ncr-sysv*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       LIBS="$LIBS -lc89"
+       AC_DEFINE(HAVE_BOGUS_SYS_QUEUE_H)
+       ;;
+*-sni-sysv*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       # /usr/ucblib MUST NOT be searched on ReliantUNIX
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       IPADDR_IN_DISPLAY=yes
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(IP_TOS_IS_BROKEN)
+       AC_DEFINE(HAVE_BOGUS_SYS_QUEUE_H)
+       # /usr/ucblib/libucb.a no longer needed on ReliantUNIX
+       # Attention: always take care to bind libsocket and libnsl before libc,
+       # otherwise you will find lots of "SIOCGPGRP errno 22" on syslog
+       ;;
+*-*-sysv4.2*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+#      enable_suid_ssh=no
+       AC_DEFINE(USE_PIPES)
+       ;;
+*-*-sysv5*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+#      enable_suid_ssh=no
+       AC_DEFINE(USE_PIPES)
+       ;;
+*-*-sysv*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       ;;
+*-*-sco3.2v4*)
+       CPPFLAGS="$CPPFLAGS -Dftruncate=chsize -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       LIBS="$LIBS -los -lprot -lx -ltinfo -lm"
+       rsh_path="/usr/bin/rcmd"
+       RANLIB=true
+       no_dev_ptmx=1
+       AC_DEFINE(BROKEN_SYS_TERMIO_H)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(HAVE_SCO_PROTECTED_PW)
+       AC_DEFINE(DISABLE_SHADOW)
+       AC_DEFINE(HAVE_BOGUS_SYS_QUEUE_H)
+       AC_DEFINE(BROKEN_SAVED_UIDS)
+       AC_CHECK_FUNCS(getluid setluid)
+       MANTYPE=man
+       do_sco3_extra_lib_check=yes
+       ;;
+*-*-sco3.2v5*)
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       LIBS="$LIBS -lprot -lx -ltinfo -lm"
+       no_dev_ptmx=1
+       rsh_path="/usr/bin/rcmd"
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(HAVE_SCO_PROTECTED_PW)
+       AC_DEFINE(DISABLE_SHADOW)
+       AC_DEFINE(HAVE_BOGUS_SYS_QUEUE_H)
+       AC_CHECK_FUNCS(getluid setluid)
+       MANTYPE=man
+       ;;
+*-*-unicos*)
+       no_libsocket=1
+       no_libnsl=1
+       AC_DEFINE(USE_PIPES)
+       LDFLAGS="$LDFLAGS -Wl,-Dmsglevel=334:fatal,-L/usr/local/lib"
+       LIBS="$LIBS -lgen -lrsc"
+       ;;
+*-dec-osf*)
+       AC_MSG_CHECKING(for Digital Unix SIA)
+       no_osfsia=""
+       AC_ARG_WITH(osfsia,
+               [  --with-osfsia           Enable Digital Unix SIA],
+               [
+                       if test "x$withval" = "xno" ; then
+                               AC_MSG_RESULT(disabled)
+                               no_osfsia=1
+                       fi
+               ],
+       )
+       if test -z "$no_osfsia" ; then
+               if test -f /etc/sia/matrix.conf; then
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_OSF_SIA)
+                       AC_DEFINE(DISABLE_LOGIN)
+                       LIBS="$LIBS -lsecurity -ldb -lm -laud"
+               else
+                       AC_MSG_RESULT(no)
+               fi
+       fi
+       ;;
+
+*-*-nto-qnx)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(NO_X11_UNIX_SOCKETS)
+       AC_DEFINE(MISSING_NFDBITS)
+       AC_DEFINE(MISSING_HOWMANY)
+       AC_DEFINE(MISSING_FD_MASK)
+       ;;
+esac
+
+# Allow user to specify flags
+AC_ARG_WITH(cflags,
+       [  --with-cflags           Specify additional flags to pass to compiler],
+       [
+               if test "x$withval" != "xno" ; then
+                       CFLAGS="$CFLAGS $withval"
+               fi
+       ]       
+)
+AC_ARG_WITH(cppflags,
+       [  --with-cppflags         Specify additional flags to pass to preprocessor] ,
+       [
+               if test "x$withval" != "xno"; then
+                       CPPFLAGS="$CPPFLAGS $withval"
+               fi
+       ]
+)
+AC_ARG_WITH(ldflags,
+       [  --with-ldflags          Specify additional flags to pass to linker],
+       [
+               if test "x$withval" != "xno" ; then
+                       LDFLAGS="$LDFLAGS $withval"
+               fi
+       ]       
+)
+AC_ARG_WITH(libs,
+       [  --with-libs             Specify additional libraries to link with],
+       [
+               if test "x$withval" != "xno" ; then
+                       LIBS="$LIBS $withval"
+               fi
+       ]       
+)
+
+AC_ARG_WITH(pcre,
+       [  --with-pcre[[=PATH]]      Override built in regex library with pcre
+                            (optionally in PATH)],
+       [
+               case "$withval" in
+               no) ;;
+               *)
+                       if test "x$withval" != "xyes"; then
+                               if test -d "$withval/lib"; then
+                                       if test -n "${need_dash_r}"; then
+                                               LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
+                                       else
+                                               LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+                                       fi
+                               else
+                                       if test -n "${need_dash_r}"; then
+                                               LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
+                                       else
+                                               LDFLAGS="-L${withval} ${LDFLAGS}"
+                                       fi
+                               fi
+                               if test -d "$withval/include"; then
+                                       CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
+                               else
+                                       CPPFLAGS="-I${withval} ${CPPFLAGS}"
+                               fi
+                       fi
+
+                       AC_CHECK_HEADER(pcreposix.h,
+                               AC_CHECK_LIB(pcre, pcre_info,[
+                                       AC_DEFINE(HAVE_LIBPCRE)
+                                       LIBS="$LIBS -lpcreposix -lpcre"
+                                       no_comp_check=yes],
+                                       AC_MSG_ERROR([*** unable to locate pcre library ***])),
+                               AC_MSG_ERROR([*** unable to locate pcreposix.h include file ***]))
+                       ;;
+               esac
+       ]       
+)
+
+# Checks for libraries.
+AC_CHECK_FUNC(yp_match, , AC_CHECK_LIB(nsl, yp_match))
+AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
+
+dnl SCO OS3 needs this for libwrap
+if test "x$with_tcp_wrappers" != "xno" ; then
+    if test "x$do_sco3_extra_lib_check" = "xyes" ; then
+       AC_CHECK_LIB(rpc, innetgr, LIBS="-lrpc -lyp -lrpc $LIBS" , , -lyp -lrpc)
+    fi
+fi
+
+AC_CHECK_FUNC(getspnam, ,
+       AC_CHECK_LIB(gen, getspnam, LIBS="$LIBS -lgen"))
+
+dnl zlib is required
+AC_ARG_WITH(zlib,
+       [  --with-zlib=PATH        Use zlib in PATH],
+       [
+               if test -d "$withval/lib"; then
+                       if test -n "${need_dash_r}"; then
+                               LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
+                       else
+                               LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+                       fi
+               else
+                       if test -n "${need_dash_r}"; then
+                               LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
+                       else
+                               LDFLAGS="-L${withval} ${LDFLAGS}"
+                       fi
+               fi
+               if test -d "$withval/include"; then
+                       CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
+               else
+                       CPPFLAGS="-I${withval} ${CPPFLAGS}"
+               fi
+       ]
+)
+
+AC_CHECK_LIB(z, deflate, ,AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***]))
+
+# We don't want to check if we did an pcre override.
+if test -z "$no_comp_check" ; then
+       AC_CHECK_FUNC(regcomp, 
+               [ AC_DEFINE(HAVE_REGCOMP)],
+               [
+                       AC_CHECK_LIB(pcre, pcre_info, 
+                       [
+                               AC_DEFINE(HAVE_LIBPCRE)
+                               LIBS="$LIBS -lpcreposix -lpcre"
+                       ],
+                       [
+                               AC_MSG_ERROR([*** No regex library found.])
+                       ])
+               ]
+       )
+fi
+
+dnl UnixWare 2.x
+AC_CHECK_FUNC(strcasecmp, 
+       [], [ AC_CHECK_LIB(resolv, strcasecmp, LIBS="$LIBS -lresolv") ]
+)
+AC_CHECK_FUNC(utimes, 
+       [], [ AC_CHECK_LIB(c89, utimes, LIBS="$LIBS -lc89") ]
+)
+
+dnl    Checks for libutil functions
+AC_CHECK_HEADERS(libutil.h)
+AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN)])
+AC_CHECK_FUNCS(logout updwtmp logwtmp)
+
+AC_FUNC_STRFTIME
+
+# Checks for header files.
+AC_CHECK_HEADERS(bstring.h crypt.h endian.h floatingpoint.h \
+       getopt.h glob.h lastlog.h limits.h login.h \
+       login_cap.h maillock.h netdb.h netgroup.h \
+       netinet/in_systm.h paths.h poll.h pty.h regex.h \
+       security/pam_appl.h shadow.h stddef.h stdint.h \
+       strings.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h \
+       sys/poll.h sys/queue.h sys/select.h sys/stat.h \
+       sys/stropts.h sys/sysmacros.h sys/time.h \
+       sys/ttcompat.h sys/un.h time.h ttyent.h usersec.h \
+       util.h utime.h utmp.h utmpx.h)
+
+# Check for ALTDIRFUNC glob() extension
+AC_MSG_CHECKING(for GLOB_ALTDIRFUNC support)
+AC_EGREP_CPP(FOUNDIT,
+       [
+               #include <glob.h>
+               #ifdef GLOB_ALTDIRFUNC
+               FOUNDIT
+               #endif
+       ], 
+       [
+               AC_DEFINE(GLOB_HAS_ALTDIRFUNC)
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+       ]
+)
+
+# Check for g.gl_matchc glob() extension
+AC_MSG_CHECKING(for gl_matchc field in glob_t)
+AC_EGREP_CPP(FOUNDIT,
+        [
+                #include <glob.h>
+               int main(void){glob_t g; g.gl_matchc = 1;}
+        ],
+        [
+                AC_DEFINE(GLOB_HAS_GL_MATCHC)
+                AC_MSG_RESULT(yes)
+        ],
+        [
+                AC_MSG_RESULT(no)
+        ]
+)
+
+AC_MSG_CHECKING([whether struct dirent allocates space for d_name])
+AC_TRY_RUN(
+       [
+#include <sys/types.h>
+#include <dirent.h>
+int main(void){struct dirent d;return(sizeof(d.d_name)<=sizeof(char));}
+       ],
+       [AC_MSG_RESULT(yes)], 
+       [
+               AC_MSG_RESULT(no)
+               AC_DEFINE(BROKEN_ONE_BYTE_DIRENT_D_NAME)
+       ]
+)
+
+# Check whether user wants S/Key support
+SKEY_MSG="no" 
+AC_ARG_WITH(skey,
+       [  --with-skey[[=PATH]]      Enable S/Key support
+                            (optionally in PATH)],
+       [
+               if test "x$withval" != "xno" ; then
+
+                       if test "x$withval" != "xyes" ; then
+                               CPPFLAGS="$CPPFLAGS -I${withval}/include"
+                               LDFLAGS="$LDFLAGS -L${withval}/lib"
+                       fi
+
+                       AC_DEFINE(SKEY)
+                       LIBS="-lskey $LIBS"
+                       SKEY_MSG="yes" 
+       
+                       AC_CHECK_FUNC(skey_keyinfo,
+                               [],
+                               [
+                                       AC_MSG_ERROR([** Incomplete or missing s/key libraries.])
+                               ])
+               fi
+       ]
+)
+
+# Check whether user wants TCP wrappers support
+TCPW_MSG="no"
+AC_ARG_WITH(tcp-wrappers,
+       [  --with-tcp-wrappers[[=PATH]]      Enable tcpwrappers support
+                            (optionally in PATH)],
+       [
+               if test "x$withval" != "xno" ; then
+                       saved_LIBS="$LIBS"
+                       saved_LDFLAGS="$LDFLAGS"
+                       saved_CPPFLAGS="$CPPFLAGS"
+                       if test -n "${withval}" -a "${withval}" != "yes"; then
+                               if test -d "${withval}/lib"; then
+                                       if test -n "${need_dash_r}"; then
+                                               LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
+                                       else
+                                               LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+                                       fi
+                               else
+                                       if test -n "${need_dash_r}"; then
+                                               LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
+                                       else
+                                               LDFLAGS="-L${withval} ${LDFLAGS}"
+                                       fi
+                               fi
+                               if test -d "${withval}/include"; then
+                                       CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
+                               else
+                                       CPPFLAGS="-I${withval} ${CPPFLAGS}"
+                               fi
+                       fi
+                       LIBS="-lwrap $LIBS"
+                       AC_MSG_CHECKING(for libwrap)
+                       AC_TRY_LINK(
+                               [
+#include <tcpd.h>
+                                       int deny_severity = 0, allow_severity = 0;
+                               ],
+                               [hosts_access(0);],
+                               [
+                                       AC_MSG_RESULT(yes)
+                                       AC_DEFINE(LIBWRAP)
+                                       TCPW_MSG="yes"
+                               ],
+                               [
+                                       AC_MSG_ERROR([*** libwrap missing])
+                               ]
+                       )
+               fi
+       ]
+)
+
+dnl    Checks for library functions.
+AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_sa \
+       clock fchmod fchown freeaddrinfo futimes gai_strerror \
+       getaddrinfo getcwd getgrouplist getnameinfo getopt \
+       getrlimit getrusage getttyent glob inet_aton inet_ntoa \
+       inet_ntop innetgr login_getcapbool md5_crypt memmove \
+       mkdtemp on_exit openpty readpassphrase realpath \
+       rresvport_af setdtablesize setegid setenv seteuid \
+       setlogin setproctitle setresgid setreuid setrlimit \
+       setsid setvbuf sigaction sigvec snprintf strerror \
+       strlcat strlcpy strmode strsep sysconf tcgetpgrp utimes \
+       vhangup vsnprintf waitpid __b64_ntop _getpty)
+
+dnl IRIX and Solaris 2.5.1 have dirname() in libgen
+AC_CHECK_FUNCS(dirname, [AC_CHECK_HEADERS(libgen.h)] ,[
+       AC_CHECK_LIB(gen, dirname,[
+               AC_CACHE_CHECK([for broken dirname],
+                       ac_cv_have_broken_dirname, [
+                       save_LIBS="$LIBS"
+                       LIBS="$LIBS -lgen"
+                       AC_TRY_RUN(
+                               [
+#include <libgen.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+    char *s, buf[32];
+
+    strncpy(buf,"/etc", 32);
+    s = dirname(buf);
+    if (!s || strncmp(s, "/", 32) != 0) {
+       exit(1);
+    } else {
+       exit(0);
+    }
+}
+                               ],
+                               [ ac_cv_have_broken_dirname="no" ],
+                               [ ac_cv_have_broken_dirname="yes" ]
+                       )
+                       LIBS="$save_LIBS"
+               ])
+               if test "x$ac_cv_have_broken_dirname" = "xno" ; then
+                       LIBS="$LIBS -lgen"
+                       AC_DEFINE(HAVE_DIRNAME)
+                       AC_CHECK_HEADERS(libgen.h)
+               fi
+       ])
+])
+
+dnl    Checks for time functions
+AC_CHECK_FUNCS(gettimeofday time)
+dnl    Checks for utmp functions
+AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
+AC_CHECK_FUNCS(utmpname)
+dnl    Checks for utmpx functions
+AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
+AC_CHECK_FUNCS(setutxent utmpxname)
+
+AC_CHECK_FUNC(getuserattr, 
+       [AC_DEFINE(HAVE_GETUSERATTR)],
+       [AC_CHECK_LIB(s, getuserattr, [LIBS="$LIBS -ls"; AC_DEFINE(HAVE_GETUSERATTR)])]
+)
+
+AC_CHECK_FUNC(daemon, 
+       [AC_DEFINE(HAVE_DAEMON)],
+       [AC_CHECK_LIB(bsd, daemon, [LIBS="$LIBS -lbsd"; AC_DEFINE(HAVE_DAEMON)])]
+)
+
+AC_CHECK_FUNC(getpagesize, 
+       [AC_DEFINE(HAVE_GETPAGESIZE)],
+       [AC_CHECK_LIB(ucb, getpagesize, [LIBS="$LIBS -lucb"; AC_DEFINE(HAVE_GETPAGESIZE)])]
+)
+
+# Check for broken snprintf
+if test "x$ac_cv_func_snprintf" = "xyes" ; then
+       AC_MSG_CHECKING([whether snprintf correctly terminates long strings])
+       AC_TRY_RUN(
+               [
+#include <stdio.h>
+int main(void){char b[5];snprintf(b,5,"123456789");return(b[4]!='\0');}
+               ],
+               [AC_MSG_RESULT(yes)], 
+               [
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(BROKEN_SNPRINTF)
+                       AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor])
+               ]
+       )
+fi
+
+AC_FUNC_GETPGRP
+
+# Check for PAM libs
+PAM_MSG="no"
+AC_ARG_WITH(pam,
+       [  --with-pam              Enable PAM support ],
+       [
+               if test "x$withval" != "xno" ; then
+                       if test "x$ac_cv_header_security_pam_appl_h" != "xyes" ; then
+                               AC_MSG_ERROR([PAM headers not found])
+                       fi
+
+                       AC_CHECK_LIB(dl, dlopen, , )
+                       AC_CHECK_LIB(pam, pam_set_item, , AC_MSG_ERROR([*** libpam missing]))
+                       AC_CHECK_FUNCS(pam_getenvlist)
+
+                       disable_shadow=yes
+                       PAM_MSG="yes"
+
+                       AC_DEFINE(USE_PAM)
+               fi
+       ]
+)
+
+# Check for older PAM
+if test "x$PAM_MSG" = "xyes" ; then
+       # Check PAM strerror arguments (old PAM)
+       AC_MSG_CHECKING([whether pam_strerror takes only one argument])
+       AC_TRY_COMPILE(
+               [
+#include <stdlib.h>
+#include <security/pam_appl.h>
+               ], 
+               [(void)pam_strerror((pam_handle_t *)NULL, -1);], 
+               [AC_MSG_RESULT(no)],
+               [
+                       AC_DEFINE(HAVE_OLD_PAM)
+                       AC_MSG_RESULT(yes)
+                       PAM_MSG="yes (old library)"
+               ]
+       )
+fi
+
+# The big search for OpenSSL
+AC_ARG_WITH(ssl-dir,
+       [  --with-ssl-dir=PATH     Specify path to OpenSSL installation ],
+       [
+               if test "x$withval" != "xno" ; then
+                       tryssldir=$withval
+               fi
+       ]
+)
+
+saved_LIBS="$LIBS"
+saved_LDFLAGS="$LDFLAGS"
+saved_CPPFLAGS="$CPPFLAGS"
+if test "x$prefix" != "xNONE" ; then
+       tryssldir="$tryssldir $prefix"
+fi
+AC_CACHE_CHECK([for OpenSSL directory], ac_cv_openssldir, [
+       for ssldir in $tryssldir "" /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do
+               CPPFLAGS="$saved_CPPFLAGS"
+               LDFLAGS="$saved_LDFLAGS"
+               LIBS="$saved_LIBS -lcrypto"
+               
+               # Skip directories if they don't exist
+               if test ! -z "$ssldir" -a ! -d "$ssldir" ; then
+                       continue;
+               fi
+               if test ! -z "$ssldir" -a "x$ssldir" != "x/usr"; then
+                       # Try to use $ssldir/lib if it exists, otherwise 
+                       # $ssldir
+                       if test -d "$ssldir/lib" ; then
+                               LDFLAGS="-L$ssldir/lib $saved_LDFLAGS"
+                               if test ! -z "$need_dash_r" ; then
+                                       LDFLAGS="-R$ssldir/lib $LDFLAGS"
+                               fi
+                       else
+                               LDFLAGS="-L$ssldir $saved_LDFLAGS"
+                               if test ! -z "$need_dash_r" ; then
+                                       LDFLAGS="-R$ssldir $LDFLAGS"
+                               fi
+                       fi
+                       # Try to use $ssldir/include if it exists, otherwise 
+                       # $ssldir
+                       if test -d "$ssldir/include" ; then
+                               CPPFLAGS="-I$ssldir/include $saved_CPPFLAGS"
+                       else
+                               CPPFLAGS="-I$ssldir $saved_CPPFLAGS"
+                       fi
+               fi
+
+               # Basic test to check for compatible version and correct linking
+               # *does not* test for RSA - that comes later.
+               AC_TRY_RUN(
+                       [
+#include <string.h>
+#include <openssl/rand.h>
+int main(void) 
+{
+       char a[2048];
+       memset(a, 0, sizeof(a));
+       RAND_add(a, sizeof(a), sizeof(a));
+       return(RAND_status() <= 0);
+}
+                       ],
+                       [
+                               found_crypto=1
+                               break;
+                       ], []
+               )
+
+               if test ! -z "$found_crypto" ; then
+                       break;
+               fi
+       done
+
+       if test -z "$found_crypto" ; then
+               AC_MSG_ERROR([Could not find working OpenSSL library, please install or check config.log])      
+       fi
+       if test -z "$ssldir" ; then
+               ssldir="(system)"
+       fi
+
+       ac_cv_openssldir=$ssldir
+])
+
+if (test ! -z "$ac_cv_openssldir" && test "x$ac_cv_openssldir" != "x(system)") ; then
+       AC_DEFINE(HAVE_OPENSSL)
+       dnl Need to recover ssldir - test above runs in subshell
+       ssldir=$ac_cv_openssldir
+       if test ! -z "$ssldir" -a "x$ssldir" != "x/usr"; then
+               # Try to use $ssldir/lib if it exists, otherwise 
+               # $ssldir
+               if test -d "$ssldir/lib" ; then
+                       LDFLAGS="-L$ssldir/lib $saved_LDFLAGS"
+                       if test ! -z "$need_dash_r" ; then
+                               LDFLAGS="-R$ssldir/lib $LDFLAGS"
+                       fi
+               else
+                       LDFLAGS="-L$ssldir $saved_LDFLAGS"
+                       if test ! -z "$need_dash_r" ; then
+                               LDFLAGS="-R$ssldir $LDFLAGS"
+                       fi
+               fi
+               # Try to use $ssldir/include if it exists, otherwise 
+               # $ssldir
+               if test -d "$ssldir/include" ; then
+                       CPPFLAGS="-I$ssldir/include $saved_CPPFLAGS"
+               else
+                       CPPFLAGS="-I$ssldir $saved_CPPFLAGS"
+               fi
+       fi
+fi
+LIBS="$saved_LIBS -lcrypto"
+
+# Now test RSA support
+saved_LIBS="$LIBS"
+AC_MSG_CHECKING([for RSA support])
+for WANTS_RSAREF in "" 1 ; do
+       if test -z "$WANTS_RSAREF" ; then
+               LIBS="$saved_LIBS"
+       else
+               LIBS="$saved_LIBS -lRSAglue -lrsaref"
+       fi
+       AC_TRY_RUN([
+#include <string.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/bn.h>
+#include <openssl/sha.h>
+int main(void) 
+{
+       int num; RSA *key; static unsigned char p_in[] = "blahblah";
+       unsigned char c[256], p[256];
+       memset(c, 0, sizeof(c)); RAND_add(c, sizeof(c), sizeof(c));
+       if ((key=RSA_generate_key(512, 3, NULL, NULL))==NULL) return(1);
+       num = RSA_public_encrypt(sizeof(p_in) - 1, p_in, c, key, RSA_PKCS1_PADDING);
+       return(-1 == RSA_private_decrypt(num, c, p, key, RSA_PKCS1_PADDING));
+}
+       ],
+       [
+               rsa_works=1
+               break;
+       ], [])
+done
+LIBS="$saved_LIBS"
+
+if test ! -z "$no_rsa" ; then
+       AC_MSG_RESULT(disabled)
+       RSA_MSG="disabled"
+else
+       if test -z "$rsa_works" ; then
+               AC_MSG_WARN([*** No RSA support found *** ])
+               RSA_MSG="no"
+       else
+               if test -z "$WANTS_RSAREF" ; then
+                       AC_MSG_RESULT(yes)
+                       RSA_MSG="yes"
+               else
+                       RSA_MSG="yes (using RSAref)"
+                       AC_MSG_RESULT(using RSAref)
+                       LIBS="$LIBS -lcrypto -lRSAglue -lrsaref"
+               fi
+       fi
+fi
+
+# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the 
+# version in OpenSSL. Skip this for PAM
+if test "x$PAM_MSG" = "xno" -a "x$check_for_libcrypt_later" = "x1"; then
+       AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
+fi
+
+# Cheap hack to ensure NEWS-OS libraries are arranged right.
+if test ! -z "$SONY" ; then
+  LIBS="$LIBS -liberty";
+fi
+
+# Checks for data types
+AC_CHECK_SIZEOF(char, 1)
+AC_CHECK_SIZEOF(short int, 2)
+AC_CHECK_SIZEOF(int, 4)
+AC_CHECK_SIZEOF(long int, 4)
+AC_CHECK_SIZEOF(long long int, 8)
+
+# More checks for data types
+AC_CACHE_CHECK([for u_int type], ac_cv_have_u_int, [
+       AC_TRY_COMPILE(
+               [ #include <sys/types.h> ], 
+               [ u_int a; a = 1;], 
+               [ ac_cv_have_u_int="yes" ],
+               [ ac_cv_have_u_int="no" ]
+       )
+])
+if test "x$ac_cv_have_u_int" = "xyes" ; then
+       AC_DEFINE(HAVE_U_INT)
+       have_u_int=1
+fi
+
+AC_CACHE_CHECK([for intXX_t types], ac_cv_have_intxx_t, [
+       AC_TRY_COMPILE(
+               [ #include <sys/types.h> ], 
+               [ int8_t a; int16_t b; int32_t c; a = b = c = 1;], 
+               [ ac_cv_have_intxx_t="yes" ],
+               [ ac_cv_have_intxx_t="no" ]
+       )
+])
+if test "x$ac_cv_have_intxx_t" = "xyes" ; then
+       AC_DEFINE(HAVE_INTXX_T)
+       have_intxx_t=1
+fi
+
+if (test -z "$have_intxx_t" && \
+           test "x$ac_cv_header_stdint_h" = "xyes")
+then
+    AC_MSG_CHECKING([for intXX_t types in stdint.h])
+       AC_TRY_COMPILE(
+               [ #include <stdint.h> ], 
+               [ int8_t a; int16_t b; int32_t c; a = b = c = 1;], 
+               [
+                       AC_DEFINE(HAVE_INTXX_T)
+                       AC_MSG_RESULT(yes)
+               ],
+               [ AC_MSG_RESULT(no) ]
+       )
+fi
+
+AC_CACHE_CHECK([for int64_t type], ac_cv_have_int64_t, [
+       AC_TRY_COMPILE(
+               [ #include <sys/types.h> ], 
+               [ int64_t a; a = 1;], 
+               [ ac_cv_have_int64_t="yes" ],
+               [ ac_cv_have_int64_t="no" ]
+       )
+])
+if test "x$ac_cv_have_int64_t" = "xyes" ; then
+       AC_DEFINE(HAVE_INT64_T)
+       have_int64_t=1
+fi
+       
+if test -z "$have_int64_t" ; then
+    AC_MSG_CHECKING([for int64_t type in sys/socket.h])
+       AC_TRY_COMPILE(
+               [ #include <sys/socket.h> ], 
+               [ int64_t a; a = 1],
+               [
+                       AC_DEFINE(HAVE_INT64_T)
+                       AC_MSG_RESULT(yes)
+               ],
+               [ AC_MSG_RESULT(no) ]
+       )
+fi
+
+AC_CACHE_CHECK([for u_intXX_t types], ac_cv_have_u_intxx_t, [
+       AC_TRY_COMPILE(
+               [ #include <sys/types.h> ], 
+               [ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;], 
+               [ ac_cv_have_u_intxx_t="yes" ],
+               [ ac_cv_have_u_intxx_t="no" ]
+       )
+])
+if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
+       AC_DEFINE(HAVE_U_INTXX_T)
+       have_u_intxx_t=1
+fi
+
+if test -z "$have_u_intxx_t" ; then
+    AC_MSG_CHECKING([for u_intXX_t types in sys/socket.h])
+       AC_TRY_COMPILE(
+               [ #include <sys/socket.h> ], 
+               [ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;], 
+               [
+                       AC_DEFINE(HAVE_U_INTXX_T)
+                       AC_MSG_RESULT(yes)
+               ],
+               [ AC_MSG_RESULT(no) ]
+       )
+fi
+
+AC_CACHE_CHECK([for u_int64_t types], ac_cv_have_u_int64_t, [
+       AC_TRY_COMPILE(
+               [ #include <sys/types.h> ], 
+               [ u_int64_t a; a = 1;], 
+               [ ac_cv_have_u_int64_t="yes" ],
+               [ ac_cv_have_u_int64_t="no" ]
+       )
+])
+if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
+       AC_DEFINE(HAVE_U_INT64_T)
+       have_u_int64_t=1
+fi
+
+if test -z "$have_u_intxx_t" ; then
+       AC_CACHE_CHECK([for uintXX_t types], ac_cv_have_uintxx_t, [
+               AC_TRY_COMPILE(
+                       [
+#include <sys/types.h>
+                       ], 
+                       [ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1; ], 
+                       [ ac_cv_have_uintxx_t="yes" ],
+                       [ ac_cv_have_uintxx_t="no" ]
+               )
+       ])
+       if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
+               AC_DEFINE(HAVE_UINTXX_T)
+       fi
+fi
+
+if test -z "$have_uintxx_t" ; then
+    AC_MSG_CHECKING([for uintXX_t types in stdint.h])
+       AC_TRY_COMPILE(
+               [ #include <stdint.h> ], 
+               [ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;], 
+               [
+                       AC_DEFINE(HAVE_UINTXX_T)
+                       AC_MSG_RESULT(yes)
+               ],
+               [ AC_MSG_RESULT(no) ]
+       )
+fi
+
+if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
+           test "x$ac_cv_header_sys_bitypes_h" = "xyes")
+then
+       AC_MSG_CHECKING([for intXX_t and u_intXX_t types in sys/bitypes.h])
+       AC_TRY_COMPILE(
+               [
+#include <sys/bitypes.h>
+               ], 
+               [
+                       int8_t a; int16_t b; int32_t c;
+                       u_int8_t e; u_int16_t f; u_int32_t g;
+                       a = b = c = e = f = g = 1;
+               ], 
+               [
+                       AC_DEFINE(HAVE_U_INTXX_T)
+                       AC_DEFINE(HAVE_INTXX_T)
+                       AC_MSG_RESULT(yes)
+               ],
+               [AC_MSG_RESULT(no)]
+       ) 
+fi
+
+
+AC_CACHE_CHECK([for u_char], ac_cv_have_u_char, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+               ],
+               [ u_char foo; foo = 125; ],
+               [ ac_cv_have_u_char="yes" ],
+               [ ac_cv_have_u_char="no" ]
+       )
+])
+if test "x$ac_cv_have_u_char" = "xyes" ; then
+       AC_DEFINE(HAVE_U_CHAR)
+fi
+
+TYPE_SOCKLEN_T
+
+AC_CACHE_CHECK([for size_t], ac_cv_have_size_t, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+               ],
+               [ size_t foo; foo = 1235; ],
+               [ ac_cv_have_size_t="yes" ],
+               [ ac_cv_have_size_t="no" ]
+       )
+])
+if test "x$ac_cv_have_size_t" = "xyes" ; then
+       AC_DEFINE(HAVE_SIZE_T)
+fi
+
+AC_CACHE_CHECK([for ssize_t], ac_cv_have_ssize_t, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+               ],
+               [ ssize_t foo; foo = 1235; ],
+               [ ac_cv_have_ssize_t="yes" ],
+               [ ac_cv_have_ssize_t="no" ]
+       )
+])
+if test "x$ac_cv_have_ssize_t" = "xyes" ; then
+       AC_DEFINE(HAVE_SSIZE_T)
+fi
+
+AC_CACHE_CHECK([for clock_t], ac_cv_have_clock_t, [
+       AC_TRY_COMPILE(
+               [
+#include <time.h>
+               ],
+               [ clock_t foo; foo = 1235; ],
+               [ ac_cv_have_clock_t="yes" ],
+               [ ac_cv_have_clock_t="no" ]
+       )
+])
+if test "x$ac_cv_have_clock_t" = "xyes" ; then
+       AC_DEFINE(HAVE_CLOCK_T)
+fi
+
+AC_CACHE_CHECK([for sa_family_t], ac_cv_have_sa_family_t, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+               ],
+               [ sa_family_t foo; foo = 1235; ],
+               [ ac_cv_have_sa_family_t="yes" ],
+               [ AC_TRY_COMPILE(
+                 [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+               ],
+               [ sa_family_t foo; foo = 1235; ],
+               [ ac_cv_have_sa_family_t="yes" ],
+
+               [ ac_cv_have_sa_family_t="no" ]
+       )]
+       )
+])
+if test "x$ac_cv_have_sa_family_t" = "xyes" ; then
+       AC_DEFINE(HAVE_SA_FAMILY_T)
+fi
+
+AC_CACHE_CHECK([for pid_t], ac_cv_have_pid_t, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+               ],
+               [ pid_t foo; foo = 1235; ],
+               [ ac_cv_have_pid_t="yes" ],
+               [ ac_cv_have_pid_t="no" ]
+       )
+])
+if test "x$ac_cv_have_pid_t" = "xyes" ; then
+       AC_DEFINE(HAVE_PID_T)
+fi
+
+AC_CACHE_CHECK([for mode_t], ac_cv_have_mode_t, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+               ],
+               [ mode_t foo; foo = 1235; ],
+               [ ac_cv_have_mode_t="yes" ],
+               [ ac_cv_have_mode_t="no" ]
+       )
+])
+if test "x$ac_cv_have_mode_t" = "xyes" ; then
+       AC_DEFINE(HAVE_MODE_T)
+fi
+
+
+AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+               ],
+               [ struct sockaddr_storage s; ],
+               [ ac_cv_have_struct_sockaddr_storage="yes" ],
+               [ ac_cv_have_struct_sockaddr_storage="no" ]
+       )
+])
+if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
+       AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
+fi
+
+AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <netinet/in.h>
+               ],
+               [ struct sockaddr_in6 s; s.sin6_family = 0; ],
+               [ ac_cv_have_struct_sockaddr_in6="yes" ],
+               [ ac_cv_have_struct_sockaddr_in6="no" ]
+       )
+])
+if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
+       AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)
+fi
+
+AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <netinet/in.h>
+               ],
+               [ struct in6_addr s; s.s6_addr[0] = 0; ],
+               [ ac_cv_have_struct_in6_addr="yes" ],
+               [ ac_cv_have_struct_in6_addr="no" ]
+       )
+])
+if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
+       AC_DEFINE(HAVE_STRUCT_IN6_ADDR)
+fi
+
+AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+               ],
+               [ struct addrinfo s; s.ai_flags = AI_PASSIVE; ],
+               [ ac_cv_have_struct_addrinfo="yes" ],
+               [ ac_cv_have_struct_addrinfo="no" ]
+       )
+])
+if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
+       AC_DEFINE(HAVE_STRUCT_ADDRINFO)
+fi
+
+AC_CACHE_CHECK([for struct timeval], ac_cv_have_struct_timeval, [
+       AC_TRY_COMPILE(
+               [ #include <sys/time.h> ], 
+               [ struct timeval tv; tv.tv_sec = 1;], 
+               [ ac_cv_have_struct_timeval="yes" ],
+               [ ac_cv_have_struct_timeval="no" ]
+       )
+])
+if test "x$ac_cv_have_struct_timeval" = "xyes" ; then
+       AC_DEFINE(HAVE_STRUCT_TIMEVAL)
+       have_struct_timeval=1
+fi
+
+# If we don't have int64_t then we can't compile sftp-server.  So don't
+# even attempt to do it. 
+if test "x$ac_cv_have_int64_t" = "xno" -a \
+       "x$ac_cv_sizeof_long_int" != "x8" -a \
+       "x$ac_cv_sizeof_long_long_int" = "x0" ; then
+       NO_SFTP='#'
+else
+dnl test snprintf (broken on SCO w/gcc)
+       AC_TRY_RUN(
+               [
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_SNPRINTF
+main()
+{
+       char buf[50];
+       char expected_out[50];
+       int mazsize = 50 ;
+#if (SIZEOF_LONG_INT == 8)
+       long int num = 0x7fffffffffffffff;
+#else
+       long long num = 0x7fffffffffffffffll;
+#endif
+       strcpy(expected_out, "9223372036854775807");
+       snprintf(buf, mazsize, "%lld", num);
+       if(strcmp(buf, expected_out) != 0)
+               exit(1);
+       exit(0);
+}
+#else
+main() { exit(0); }
+#endif
+               ], [ true ], [ AC_DEFINE(BROKEN_SNPRINTF) ]
+       )
+fi
+AC_SUBST(NO_SFTP)
+
+dnl Checks for structure members
+OSSH_CHECK_HEADER_FOR_FIELD(ut_host, utmp.h, HAVE_HOST_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_host, utmpx.h, HAVE_HOST_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(syslen, utmpx.h, HAVE_SYSLEN_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_pid, utmp.h, HAVE_PID_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_type, utmp.h, HAVE_TYPE_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_type, utmpx.h, HAVE_TYPE_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_tv, utmp.h, HAVE_TV_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_id, utmp.h, HAVE_ID_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_id, utmpx.h, HAVE_ID_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_addr, utmp.h, HAVE_ADDR_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_addr, utmpx.h, HAVE_ADDR_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_addr_v6, utmp.h, HAVE_ADDR_V6_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_addr_v6, utmpx.h, HAVE_ADDR_V6_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_exit, utmp.h, HAVE_EXIT_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_time, utmp.h, HAVE_TIME_IN_UTMP)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_time, utmpx.h, HAVE_TIME_IN_UTMPX)
+OSSH_CHECK_HEADER_FOR_FIELD(ut_tv, utmpx.h, HAVE_TV_IN_UTMPX)
+
+AC_CHECK_MEMBERS([struct stat.st_blksize])
+
+AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage],
+               ac_cv_have_ss_family_in_struct_ss, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+               ],
+               [ struct sockaddr_storage s; s.ss_family = 1; ],
+               [ ac_cv_have_ss_family_in_struct_ss="yes" ],
+               [ ac_cv_have_ss_family_in_struct_ss="no" ],
+       )
+])
+if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then
+       AC_DEFINE(HAVE_SS_FAMILY_IN_SS)
+fi
+
+AC_CACHE_CHECK([for __ss_family field in struct sockaddr_storage],
+               ac_cv_have___ss_family_in_struct_ss, [
+       AC_TRY_COMPILE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+               ],
+               [ struct sockaddr_storage s; s.__ss_family = 1; ],
+               [ ac_cv_have___ss_family_in_struct_ss="yes" ],
+               [ ac_cv_have___ss_family_in_struct_ss="no" ]
+       )
+])
+if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then
+       AC_DEFINE(HAVE___SS_FAMILY_IN_SS)
+fi
+
+AC_CACHE_CHECK([for pw_class field in struct passwd],
+               ac_cv_have_pw_class_in_struct_passwd, [
+       AC_TRY_COMPILE(
+               [
+#include <pwd.h>
+               ],
+               [ struct passwd p; p.pw_class = 0; ],
+               [ ac_cv_have_pw_class_in_struct_passwd="yes" ],
+               [ ac_cv_have_pw_class_in_struct_passwd="no" ]
+       )
+])
+if test "x$ac_cv_have_pw_class_in_struct_passwd" = "xyes" ; then
+       AC_DEFINE(HAVE_PW_CLASS_IN_PASSWD)
+fi
+
+AC_CACHE_CHECK([for pw_expire field in struct passwd],
+               ac_cv_have_pw_expire_in_struct_passwd, [
+       AC_TRY_COMPILE(
+               [
+#include <pwd.h>
+               ],
+               [ struct passwd p; p.pw_expire = 0; ],
+               [ ac_cv_have_pw_expire_in_struct_passwd="yes" ],
+               [ ac_cv_have_pw_expire_in_struct_passwd="no" ]
+       )
+])
+if test "x$ac_cv_have_pw_expire_in_struct_passwd" = "xyes" ; then
+       AC_DEFINE(HAVE_PW_EXPIRE_IN_PASSWD)
+fi
+
+AC_CACHE_CHECK([for pw_change field in struct passwd],
+               ac_cv_have_pw_change_in_struct_passwd, [
+       AC_TRY_COMPILE(
+               [
+#include <pwd.h>
+               ],
+               [ struct passwd p; p.pw_change = 0; ],
+               [ ac_cv_have_pw_change_in_struct_passwd="yes" ],
+               [ ac_cv_have_pw_change_in_struct_passwd="no" ]
+       )
+])
+if test "x$ac_cv_have_pw_change_in_struct_passwd" = "xyes" ; then
+       AC_DEFINE(HAVE_PW_CHANGE_IN_PASSWD)
+fi
+
+AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [
+       AC_TRY_LINK([], 
+               [ extern char *__progname; printf("%s", __progname); ], 
+               [ ac_cv_libc_defines___progname="yes" ],
+               [ ac_cv_libc_defines___progname="no" ]
+       )
+])
+if test "x$ac_cv_libc_defines___progname" = "xyes" ; then
+       AC_DEFINE(HAVE___PROGNAME)
+fi
+
+AC_CACHE_CHECK([whether getopt has optreset support],
+               ac_cv_have_getopt_optreset, [
+       AC_TRY_LINK(
+               [
+#include <getopt.h>
+               ],
+               [ extern int optreset; optreset = 0; ],
+               [ ac_cv_have_getopt_optreset="yes" ],
+               [ ac_cv_have_getopt_optreset="no" ]
+       )
+])
+if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then
+       AC_DEFINE(HAVE_GETOPT_OPTRESET)
+fi
+
+AC_CACHE_CHECK([if libc defines sys_errlist], ac_cv_libc_defines_sys_errlist, [
+       AC_TRY_LINK([], 
+               [ extern const char *const sys_errlist[]; printf("%s", sys_errlist[0]);], 
+               [ ac_cv_libc_defines_sys_errlist="yes" ],
+               [ ac_cv_libc_defines_sys_errlist="no" ]
+       )
+])
+if test "x$ac_cv_libc_defines_sys_errlist" = "xyes" ; then
+       AC_DEFINE(HAVE_SYS_ERRLIST)
+fi
+
+
+AC_CACHE_CHECK([if libc defines sys_nerr], ac_cv_libc_defines_sys_nerr, [
+       AC_TRY_LINK([], 
+               [ extern int sys_nerr; printf("%i", sys_nerr);], 
+               [ ac_cv_libc_defines_sys_nerr="yes" ],
+               [ ac_cv_libc_defines_sys_nerr="no" ]
+       )
+])
+if test "x$ac_cv_libc_defines_sys_nerr" = "xyes" ; then
+       AC_DEFINE(HAVE_SYS_NERR)
+fi
+
+
+# Check whether user wants Kerberos support
+SCARD_MSG="no" 
+AC_ARG_WITH(smartcard,
+       [  --with-smartcard        Enable smartcard support],
+       [
+               if test "x$withval" != "xno" ; then
+                       if test "x$withval" != "xyes" ; then
+                               CPPFLAGS="$CPPFLAGS -I${withval}"
+                               LDFLAGS="$LDFLAGS -L${withval}"
+                               if test ! -z "$need_dash_r" ; then
+                                       LDFLAGS="$LDFLAGS -R${withval}"
+                               fi
+                               if test ! -z "$blibpath" ; then
+                                       blibpath="$blibpath:${withval}"
+                               fi
+                       fi
+                       AC_CHECK_HEADERS(sectok.h)
+                       if test "$ac_cv_header_sectok_h" != yes; then
+                               AC_MSG_ERROR(Can't find sectok.h)
+                       fi
+                       AC_CHECK_LIB(sectok, sectok_open)
+                       if test "$ac_cv_lib_sectok_sectok_open" != yes; then
+                               AC_MSG_ERROR(Can't find libsectok)
+                       fi
+                       AC_DEFINE(SMARTCARD)
+                       SCARD_MSG="yes" 
+               fi
+       ]
+)
+
+# Check whether user wants Kerberos support
+KRB4_MSG="no" 
+AC_ARG_WITH(kerberos4,
+       [  --with-kerberos4=PATH   Enable Kerberos 4 support],
+       [
+               if test "x$withval" != "xno" ; then
+                       if test "x$withval" != "xyes" ; then
+                               CPPFLAGS="$CPPFLAGS -I${withval}/include"
+                               LDFLAGS="$LDFLAGS -L${withval}/lib"
+                               if test ! -z "$need_dash_r" ; then
+                                       LDFLAGS="$LDFLAGS -R${withval}/lib"
+                               fi
+                               if test ! -z "$blibpath" ; then
+                                       blibpath="$blibpath:${withval}/lib"
+                               fi
+                       else
+                               if test -d /usr/include/kerberosIV ; then
+                                       CPPFLAGS="$CPPFLAGS -I/usr/include/kerberosIV"
+                               fi
+                       fi
+
+                       AC_CHECK_HEADERS(krb.h)
+                       if test "$ac_cv_header_krb_h" != yes; then
+                               AC_MSG_WARN([Cannot find krb.h, build may fail])
+                       fi
+                       AC_CHECK_LIB(krb, main)
+                       if test "$ac_cv_lib_krb_main" != yes; then
+                               AC_CHECK_LIB(krb4, main)
+                               if test "$ac_cv_lib_krb4_main" != yes; then
+                                       AC_MSG_WARN([Cannot find libkrb nor libkrb4, build may fail])
+                               else
+                                       KLIBS="-lkrb4"
+                               fi
+                       else
+                               KLIBS="-lkrb"
+                       fi
+                       AC_CHECK_LIB(des, des_cbc_encrypt)
+                       if test "$ac_cv_lib_des_des_cbc_encrypt" != yes; then
+                               AC_CHECK_LIB(des425, des_cbc_encrypt)
+                               if test "$ac_cv_lib_des425_des_cbc_encrypt" != yes; then
+                                       AC_MSG_WARN([Cannot find libdes nor libdes425, build may fail])
+                               else
+                                       KLIBS="-ldes425"
+                               fi
+                       else
+                               KLIBS="-ldes"
+                       fi
+                       AC_CHECK_LIB(resolv, dn_expand, , )
+                       KRB4=yes
+                       KRB4_MSG="yes" 
+                       AC_DEFINE(KRB4)
+               fi
+       ]
+)
+
+# Check whether user wants AFS support
+AFS_MSG="no" 
+AC_ARG_WITH(afs,
+       [  --with-afs=PATH         Enable AFS support],
+       [
+               if test "x$withval" != "xno" ; then
+
+                       if test "x$withval" != "xyes" ; then
+                               CPPFLAGS="$CPPFLAGS -I${withval}/include"
+                               LDFLAGS="$LDFLAGS -L${withval}/lib"
+                       fi
+
+                       if test -z "$KRB4" ; then
+                               AC_MSG_WARN([AFS requires Kerberos IV support, build may fail])
+                       fi
+
+                       LIBS="-lkafs $LIBS"
+                       if test ! -z "$AFS_LIBS" ; then
+                               LIBS="$LIBS $AFS_LIBS"
+                       fi
+                       AC_DEFINE(AFS)
+                       AFS_MSG="yes" 
+               fi
+       ]
+)
+LIBS="$LIBS $KLIBS"
+
+# Looking for programs, paths and files
+AC_ARG_WITH(rsh,
+       [  --with-rsh=PATH         Specify path to remote shell program ],
+       [
+               if test "x$withval" != "$no" ; then
+                       rsh_path=$withval
+               fi
+       ],
+       [
+               AC_PATH_PROG(rsh_path, rsh)
+       ]
+)
+
+AC_ARG_WITH(xauth,
+       [  --with-xauth=PATH       Specify path to xauth program ],
+       [
+               if test "x$withval" != "xno" ; then
+                       xauth_path=$withval
+               fi
+       ],
+       [
+               AC_PATH_PROG(xauth_path, xauth,,$PATH:/usr/X/bin:/usr/bin/X11:/usr/X11R6/bin:/usr/openwin/bin)
+               if (test ! -z "$xauth_path" && test -x "/usr/openwin/bin/xauth") ; then
+                       xauth_path="/usr/openwin/bin/xauth"
+               fi
+       ]
+)
+
+if test -z "$xauth_path" ; then
+       XAUTH_PATH="undefined"
+       AC_SUBST(XAUTH_PATH)
+else
+       AC_DEFINE_UNQUOTED(XAUTH_PATH, "$xauth_path")
+       XAUTH_PATH=$xauth_path
+       AC_SUBST(XAUTH_PATH)
+fi
+if test ! -z "$rsh_path" ; then
+       AC_DEFINE_UNQUOTED(RSH_PATH, "$rsh_path")
+fi
+
+# Check for mail directory (last resort if we cannot get it from headers)
+if test ! -z "$MAIL" ; then
+       maildir=`dirname $MAIL`
+       AC_DEFINE_UNQUOTED(MAIL_DIRECTORY, "$maildir")
+fi
+
+if test -z "$no_dev_ptmx" ; then
+       AC_CHECK_FILE("/dev/ptmx", 
+               [
+                       AC_DEFINE_UNQUOTED(HAVE_DEV_PTMX)
+                       have_dev_ptmx=1
+               ]
+       )
+fi
+AC_CHECK_FILE("/dev/ptc", 
+       [
+               AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC)
+               have_dev_ptc=1
+       ]
+)
+
+# Options from here on. Some of these are preset by platform above
+
+# Check for user-specified random device, otherwise check /dev/urandom
+AC_ARG_WITH(random,
+       [  --with-random=FILE      read entropy from FILE (default=/dev/urandom)],
+       [
+               if test "x$withval" != "xno" ; then
+                       RANDOM_POOL="$withval";
+                       AC_DEFINE_UNQUOTED(RANDOM_POOL, "$RANDOM_POOL")
+               fi
+       ],
+       [
+               # Check for random device
+               AC_CHECK_FILE("/dev/urandom",
+                       [
+                               RANDOM_POOL="/dev/urandom"; 
+                               AC_SUBST(RANDOM_POOL)
+                               AC_DEFINE_UNQUOTED(RANDOM_POOL, "$RANDOM_POOL")
+                       ]
+               )
+       ]
+)
+
+# Check for PRNGD/EGD pool file
+AC_ARG_WITH(prngd-port,
+       [  --with-prngd-port=PORT  read entropy from PRNGD/EGD localhost:PORT],
+       [
+               if test ! -z "$withval" -a "x$withval" != "xno" ; then
+                       PRNGD_PORT="$withval"
+                       AC_DEFINE_UNQUOTED(PRNGD_PORT, $PRNGD_PORT)
+               fi
+       ]
+)
+
+# Check for PRNGD/EGD pool file
+AC_ARG_WITH(prngd-socket,
+       [  --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)],
+       [
+               if test "x$withval" != "xno" ; then
+                       PRNGD_SOCKET="$withval"
+                       AC_DEFINE_UNQUOTED(PRNGD_SOCKET, "$PRNGD_SOCKET")
+               fi
+       ],
+       [
+               # Check for existing socket only if we don't have a random device already
+               if test -z "$RANDOM_POOL" ; then
+                       AC_MSG_CHECKING(for PRNGD/EGD socket)
+                       # Insert other locations here
+                       for sock in /var/run/egd-pool /dev/egd-pool /etc/entropy; do
+                               if test -r $sock && $TEST_MINUS_S_SH -c "test -S $sock -o -p $sock" ; then
+                                       PRNGD_SOCKET="$sock"
+                                       AC_DEFINE_UNQUOTED(PRNGD_SOCKET, "$PRNGD_SOCKET")
+                                       break;
+                               fi
+                       done
+                       if test ! -z "$PRNGD_SOCKET" ; then
+                               AC_MSG_RESULT($PRNGD_SOCKET)
+                       else
+                               AC_MSG_RESULT(not found)
+                       fi
+               fi
+       ]
+)
+
+
+# detect pathnames for entropy gathering commands, if we need them
+INSTALL_SSH_PRNG_CMDS=""
+rm -f prng_commands
+if (test -z "$RANDOM_POOL" && test -z "$PRNGD") ; then
+       # Use these commands to collect entropy
+       OSSH_PATH_ENTROPY_PROG(PROG_LS, ls)
+       OSSH_PATH_ENTROPY_PROG(PROG_NETSTAT, netstat)
+       OSSH_PATH_ENTROPY_PROG(PROG_ARP, arp)
+       OSSH_PATH_ENTROPY_PROG(PROG_IFCONFIG, ifconfig)
+       OSSH_PATH_ENTROPY_PROG(PROG_JSTAT, jstat)
+       OSSH_PATH_ENTROPY_PROG(PROG_PS, ps)
+       OSSH_PATH_ENTROPY_PROG(PROG_SAR, sar)
+       OSSH_PATH_ENTROPY_PROG(PROG_W, w)
+       OSSH_PATH_ENTROPY_PROG(PROG_WHO, who)
+       OSSH_PATH_ENTROPY_PROG(PROG_LAST, last)
+       OSSH_PATH_ENTROPY_PROG(PROG_LASTLOG, lastlog)
+       OSSH_PATH_ENTROPY_PROG(PROG_DF, df)
+       OSSH_PATH_ENTROPY_PROG(PROG_VMSTAT, vmstat)
+       OSSH_PATH_ENTROPY_PROG(PROG_UPTIME, uptime)
+       OSSH_PATH_ENTROPY_PROG(PROG_IPCS, ipcs)
+       OSSH_PATH_ENTROPY_PROG(PROG_TAIL, tail)
+
+       INSTALL_SSH_PRNG_CMDS="yes"
+fi
+AC_SUBST(INSTALL_SSH_PRNG_CMDS)
+
+
+AC_ARG_WITH(mantype,
+       [  --with-mantype=man|cat|doc  Set man page type],
+       [
+               case "$withval" in
+               man|cat|doc)
+                       MANTYPE=$withval
+                       ;;
+               *)
+                       AC_MSG_ERROR(invalid man type: $withval)
+                       ;;
+               esac
+       ]
+)
+if test -z "$MANTYPE"; then
+       AC_PATH_PROGS(NROFF, nroff awf, /bin/false, /usr/bin:/usr/ucb)
+       if ${NROFF} -mdoc ${srcdir}/ssh.1 >/dev/null 2>&1; then
+               MANTYPE=doc
+       elif ${NROFF} -man ${srcdir}/ssh.1 >/dev/null 2>&1; then
+               MANTYPE=man
+       else
+               MANTYPE=cat
+       fi
+fi
+AC_SUBST(MANTYPE)
+if test "$MANTYPE" = "doc"; then
+       mansubdir=man;
+else
+       mansubdir=$MANTYPE;
+fi
+AC_SUBST(mansubdir)
+
+# Check whether to enable MD5 passwords
+MD5_MSG="no" 
+AC_ARG_WITH(md5-passwords,
+       [  --with-md5-passwords    Enable use of MD5 passwords],
+       [
+               if test "x$withval" != "xno" ; then
+                       AC_DEFINE(HAVE_MD5_PASSWORDS)
+                       MD5_MSG="yes" 
+               fi
+       ]
+)
+
+# Whether to disable shadow password support
+AC_ARG_WITH(shadow,
+       [  --without-shadow        Disable shadow password support],
+       [
+               if test "x$withval" = "xno" ; then      
+                       AC_DEFINE(DISABLE_SHADOW)
+                       disable_shadow=yes
+               fi
+       ]
+)
+
+if test -z "$disable_shadow" ; then
+       AC_MSG_CHECKING([if the systems has expire shadow information])
+       AC_TRY_COMPILE(
+       [
+#include <sys/types.h>
+#include <shadow.h>
+       struct spwd sp;
+       ],[ sp.sp_expire = sp.sp_lstchg = sp.sp_inact = 0; ],
+       [ sp_expire_available=yes ], []
+       )
+
+       if test "x$sp_expire_available" = "xyes" ; then
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAS_SHADOW_EXPIRE)
+       else
+               AC_MSG_RESULT(no)
+       fi
+fi
+
+# Use ip address instead of hostname in $DISPLAY
+if test ! -z "$IPADDR_IN_DISPLAY" ; then
+       DISPLAY_HACK_MSG="yes"
+       AC_DEFINE(IPADDR_IN_DISPLAY)
+else
+       DISPLAY_HACK_MSG="no" 
+       AC_ARG_WITH(ipaddr-display,
+               [  --with-ipaddr-display   Use ip address instead of hostname in \$DISPLAY],
+               [
+                       if test "x$withval" != "xno" ; then     
+                               AC_DEFINE(IPADDR_IN_DISPLAY)
+                               DISPLAY_HACK_MSG="yes" 
+                       fi
+               ]
+       )
+fi
+
+# Whether to mess with the default path
+SERVER_PATH_MSG="(default)" 
+AC_ARG_WITH(default-path,
+       [  --with-default-path=PATH Specify default \$PATH environment for server],
+       [
+               if test "x$withval" != "xno" ; then     
+                       user_path="$withval"
+                       SERVER_PATH_MSG="$withval" 
+               fi
+       ],
+       [
+       AC_TRY_RUN(
+               [
+/* find out what STDPATH is */
+#include <stdio.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#ifndef _PATH_STDPATH
+# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define DATA "conftest.stdpath"
+
+main()
+{
+       FILE *fd;
+       int rc;
+       
+       fd = fopen(DATA,"w");
+       if(fd == NULL)
+               exit(1);
+       
+       if ((rc = fprintf(fd,"%s", _PATH_STDPATH)) < 0)
+               exit(1);
+
+       exit(0);
+}
+               ], [ user_path=`cat conftest.stdpath` ],
+               [ user_path="/usr/bin:/bin:/usr/sbin:/sbin" ],
+               [ user_path="/usr/bin:/bin:/usr/sbin:/sbin" ]
+       )
+# make sure $bindir is in USER_PATH so scp will work
+               t_bindir=`eval echo ${bindir}`
+               case $t_bindir in
+                       NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$prefix~"` ;;
+               esac
+               case $t_bindir in
+                       NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$ac_default_prefix~"` ;;
+               esac
+               echo $user_path | grep ":$t_bindir"  > /dev/null 2>&1
+               if test $? -ne 0  ; then
+                       echo $user_path | grep "^$t_bindir"  > /dev/null 2>&1
+                       if test $? -ne 0  ; then
+                               user_path=$user_path:$t_bindir
+                               AC_MSG_RESULT(Adding $t_bindir to USER_PATH so scp will work)
+                       fi
+               fi
+       ]
+)
+AC_DEFINE_UNQUOTED(USER_PATH, "$user_path")
+AC_SUBST(user_path)
+
+# Whether to force IPv4 by default (needed on broken glibc Linux)
+IPV4_HACK_MSG="no" 
+AC_ARG_WITH(ipv4-default,
+       [  --with-ipv4-default     Use IPv4 by connections unless '-6' specified],
+       [
+               if test "x$withval" != "xno" ; then     
+                       AC_DEFINE(IPV4_DEFAULT)
+                       IPV4_HACK_MSG="yes" 
+               fi
+       ]
+)
+
+AC_MSG_CHECKING([if we need to convert IPv4 in IPv6-mapped addresses])
+IPV4_IN6_HACK_MSG="no" 
+AC_ARG_WITH(4in6,
+       [  --with-4in6             Check for and convert IPv4 in IPv6 mapped addresses],
+       [
+               if test "x$withval" != "xno" ; then
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(IPV4_IN_IPV6)
+                       IPV4_IN6_HACK_MSG="yes" 
+               else
+                       AC_MSG_RESULT(no)
+               fi
+       ],[
+               if test "x$inet6_default_4in6" = "xyes"; then
+                       AC_MSG_RESULT([yes (default)])
+                       AC_DEFINE(IPV4_IN_IPV6)
+                       IPV4_IN6_HACK_MSG="yes" 
+               else
+                       AC_MSG_RESULT([no (default)])
+               fi
+       ]
+)
+
+# Whether to enable BSD auth support
+AC_ARG_WITH(bsd-auth,
+       [  --with-bsd-auth         Enable BSD auth support],
+       [
+               if test "x$withval" != "xno" ; then     
+                       AC_DEFINE(BSD_AUTH)
+                       bsd_auth=yes
+               fi
+       ]
+)
+
+AC_MSG_CHECKING(whether to install ssh as suid root)
+AC_ARG_ENABLE(suid-ssh,
+[  --enable-suid-ssh       Install ssh as suid root (default)
+  --disable-suid-ssh      Install ssh without suid bit],
+[ case "$enableval" in
+  no)
+       AC_MSG_RESULT(no)
+       SSHMODE=0711
+       ;;
+  *)   AC_MSG_RESULT(yes)
+       SSHMODE=4711
+       ;;
+  esac ],
+  AC_MSG_RESULT(yes)
+  SSHMODE=4711
+)
+AC_SUBST(SSHMODE)
+
+
+# Where to place sshd.pid
+piddir=/var/run
+AC_ARG_WITH(pid-dir,
+       [  --with-pid-dir=PATH     Specify location of ssh.pid file],
+       [
+               if test "x$withval" != "xno" ; then     
+                       piddir=$withval
+               fi
+       ]
+)
+
+# make sure the directory exists
+if test ! -d $piddir ; then    
+       piddir=`eval echo ${sysconfdir}`
+       case $piddir in
+               NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;;
+       esac
+fi
+
+AC_DEFINE_UNQUOTED(_PATH_SSH_PIDDIR, "$piddir")
+AC_SUBST(piddir)
+
+dnl allow user to disable some login recording features
+AC_ARG_ENABLE(lastlog,
+       [  --disable-lastlog       disable use of lastlog even if detected [no]],
+       [ AC_DEFINE(DISABLE_LASTLOG) ]
+)
+AC_ARG_ENABLE(utmp,
+       [  --disable-utmp          disable use of utmp even if detected [no]],
+       [ AC_DEFINE(DISABLE_UTMP) ]
+)
+AC_ARG_ENABLE(utmpx,
+       [  --disable-utmpx         disable use of utmpx even if detected [no]],
+       [ AC_DEFINE(DISABLE_UTMPX) ]
+)
+AC_ARG_ENABLE(wtmp,
+       [  --disable-wtmp          disable use of wtmp even if detected [no]],
+       [ AC_DEFINE(DISABLE_WTMP) ]
+)
+AC_ARG_ENABLE(wtmpx,
+       [  --disable-wtmpx         disable use of wtmpx even if detected [no]],
+       [ AC_DEFINE(DISABLE_WTMPX) ]
+)
+AC_ARG_ENABLE(libutil,
+       [  --disable-libutil       disable use of libutil (login() etc.) [no]],
+       [ AC_DEFINE(DISABLE_LOGIN) ]
+)
+AC_ARG_ENABLE(pututline,
+       [  --disable-pututline     disable use of pututline() etc. ([uw]tmp) [no]],
+       [ AC_DEFINE(DISABLE_PUTUTLINE) ]
+)
+AC_ARG_ENABLE(pututxline,
+       [  --disable-pututxline    disable use of pututxline() etc. ([uw]tmpx) [no]],
+       [ AC_DEFINE(DISABLE_PUTUTXLINE) ]
+)
+AC_ARG_WITH(lastlog,
+  [  --with-lastlog=FILE|DIR specify lastlog location [common locations]],
+       [
+               if test "x$withval" = "xno" ; then      
+                       AC_DEFINE(DISABLE_LASTLOG)
+               else
+                       conf_lastlog_location=$withval
+               fi
+       ]
+)
+
+dnl lastlog, [uw]tmpx? detection
+dnl  NOTE: set the paths in the platform section to avoid the
+dnl   need for command-line parameters
+dnl lastlog and [uw]tmp are subject to a file search if all else fails
+
+dnl lastlog detection
+dnl  NOTE: the code itself will detect if lastlog is a directory
+AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+#ifdef HAVE_LOGIN_H
+# include <login.h>
+#endif
+       ],
+       [ char *lastlog = LASTLOG_FILE; ],
+       [ AC_MSG_RESULT(yes) ],
+       [
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
+               AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+               ],
+               [ char *lastlog = _PATH_LASTLOG; ],
+               [ AC_MSG_RESULT(yes) ],
+               [
+                       AC_MSG_RESULT(no)
+                       system_lastlog_path=no
+               ])
+       ]
+)
+
+if test -z "$conf_lastlog_location"; then
+       if test x"$system_lastlog_path" = x"no" ; then
+               for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
+                               if (test -d "$f" || test -f "$f") ; then
+                                       conf_lastlog_location=$f
+                               fi
+               done
+               if test -z "$conf_lastlog_location"; then
+                       AC_MSG_WARN([** Cannot find lastlog **])
+                       dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
+               fi
+       fi
+fi
+
+if test -n "$conf_lastlog_location"; then
+       AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location")
+fi     
+
+dnl utmp detection
+AC_MSG_CHECKING([if your system defines UTMP_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+       ],
+       [ char *utmp = UTMP_FILE; ],
+       [ AC_MSG_RESULT(yes) ],
+       [ AC_MSG_RESULT(no)
+         system_utmp_path=no ]
+)
+if test -z "$conf_utmp_location"; then
+       if test x"$system_utmp_path" = x"no" ; then
+               for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
+                       if test -f $f ; then
+                               conf_utmp_location=$f
+                       fi
+               done
+               if test -z "$conf_utmp_location"; then
+                       AC_DEFINE(DISABLE_UTMP)
+               fi
+       fi
+fi
+if test -n "$conf_utmp_location"; then
+       AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location")
+fi     
+
+dnl wtmp detection
+AC_MSG_CHECKING([if your system defines WTMP_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+       ],
+       [ char *wtmp = WTMP_FILE; ],
+       [ AC_MSG_RESULT(yes) ],
+       [ AC_MSG_RESULT(no)
+         system_wtmp_path=no ]
+)
+if test -z "$conf_wtmp_location"; then
+       if test x"$system_wtmp_path" = x"no" ; then
+               for f in /usr/adm/wtmp /var/log/wtmp; do
+                       if test -f $f ; then
+                               conf_wtmp_location=$f
+                       fi
+               done
+               if test -z "$conf_wtmp_location"; then
+                       AC_DEFINE(DISABLE_WTMP)
+               fi
+       fi
+fi
+if test -n "$conf_wtmp_location"; then
+       AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location")
+fi     
+
+
+dnl utmpx detection - I don't know any system so perverse as to require
+dnl  utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
+dnl  there, though.
+AC_MSG_CHECKING([if your system defines UTMPX_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+       ],
+       [ char *utmpx = UTMPX_FILE; ],
+       [ AC_MSG_RESULT(yes) ],
+       [ AC_MSG_RESULT(no)
+         system_utmpx_path=no ]
+)
+if test -z "$conf_utmpx_location"; then
+       if test x"$system_utmpx_path" = x"no" ; then
+               AC_DEFINE(DISABLE_UTMPX)
+       fi
+else
+       AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location")
+fi     
+
+dnl wtmpx detection
+AC_MSG_CHECKING([if your system defines WTMPX_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+       ],
+       [ char *wtmpx = WTMPX_FILE; ],
+       [ AC_MSG_RESULT(yes) ],
+       [ AC_MSG_RESULT(no)
+         system_wtmpx_path=no ]
+)
+if test -z "$conf_wtmpx_location"; then
+       if test x"$system_wtmpx_path" = x"no" ; then
+               AC_DEFINE(DISABLE_WTMPX)
+       fi
+else
+       AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location")
+fi     
+
+
+# Change default command timeout for builtin PRNG
+entropy_timeout=200
+AC_ARG_WITH(entropy-timeout,
+       [  --with-entropy-timeout  Specify entropy gathering command timeout (msec)],
+       [
+               if test "x$withval" != "xno" ; then
+                       entropy_timeout=$withval
+               fi
+       ]       
+)
+AC_DEFINE_UNQUOTED(ENTROPY_TIMEOUT_MSEC, $entropy_timeout)
+
+
+if test ! -z "$blibpath" ; then
+       LDFLAGS="$LDFLAGS -blibpath:$blibpath"
+       AC_MSG_WARN([Please check and edit -blibpath in LDFLAGS in Makefile])
+fi
+
+AC_EXEEXT
+
+AC_CONFIG_FILES([Makefile openbsd-compat/Makefile scard/Makefile ssh_prng_cmds])
+AC_OUTPUT
+
+# Print summary of options
+
+if test ! -z "$RANDOM_POOL" ; then
+       RAND_MSG="Device ($RANDOM_POOL)"
+else
+       if test ! -z "$PRNGD_PORT" ; then
+               RAND_MSG="PRNGD/EGD (port localhost:$PRNGD_PORT)"
+       elif test ! -z "$PRNGD_SOCKET" ; then
+               RAND_MSG="PRNGD/EGD (socket $PRNGD_SOCKET)"
+       else
+               RAND_MSG="Builtin (timeout $entropy_timeout)"
+               BUILTIN_RNG=1
+       fi
+fi
+
+# Someone please show me a better way :)
+A=`eval echo ${prefix}` ; A=`eval echo ${A}`
+B=`eval echo ${bindir}` ; B=`eval echo ${B}`
+C=`eval echo ${sbindir}` ; C=`eval echo ${C}`
+D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}`
+E=`eval echo ${libexecdir}/ssh-askpass` ; E=`eval echo ${E}`
+F=`eval echo ${mandir}/${mansubdir}X` ; F=`eval echo ${F}`
+G=`eval echo ${piddir}` ; G=`eval echo ${G}`
+H=`eval echo ${user_path}` ; H=`eval echo ${H}`
+
+echo ""
+echo "OpenSSH has been configured with the following options:"
+echo "                 User binaries: $B"
+echo "               System binaries: $C"
+echo "           Configuration files: $D"
+echo "               Askpass program: $E"
+echo "                  Manual pages: $F"
+echo "                      PID file: $G"
+echo "        sshd default user PATH: $H"
+echo "      Random number collection: $RAND_MSG"
+echo "                Manpage format: $MANTYPE"
+echo "                   PAM support: ${PAM_MSG}"
+echo "            KerberosIV support: $KRB4_MSG"
+echo "             Smartcard support: $SCARD_MSG"
+echo "                   AFS support: $AFS_MSG"
+echo "                 S/KEY support: $SKEY_MSG"
+echo "          TCP Wrappers support: $TCPW_MSG"
+echo "          MD5 password support: $MD5_MSG"
+echo "   IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
+echo "      Use IPv4 by default hack: $IPV4_HACK_MSG"
+echo "       Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
+
+if test ! -z "$bsd_auth"; then
+       echo "              BSD Auth support: yes"
+fi
+
+echo ""
+
+echo "              Host: ${host}"
+echo "          Compiler: ${CC}"
+echo "    Compiler flags: ${CFLAGS}"
+echo "Preprocessor flags: ${CPPFLAGS}"
+echo "      Linker flags: ${LDFLAGS}"
+echo "         Libraries: ${LIBS}"
+
+echo ""
+
+if test "x$PAM_MSG" = "xyes" ; then
+       echo "PAM is enabled. You may need to install a PAM control file for sshd,"
+       echo "otherwise password authentication may fail. Example PAM control files"
+       echo "can be found in the contrib/ subdirectory"
+       echo ""
+fi
+
+if test ! -z "$BUILTIN_RNG" ; then
+       echo "WARNING: you are using the builtin random number collection service."
+       echo "Please read WARNING.RNG and request that your OS vendor includes"
+       echo "/dev/random in future versions of their OS."
+       echo ""
+fi
+
+if test ! -z "$NO_SFTP"; then
+       echo "sftp-server will be disabled.  Your compiler does not support"
+       echo "64bit integers."
+       echo ""
+fi
+
diff --git a/openssh/contrib/README b/openssh/contrib/README
new file mode 100644 (file)
index 0000000..d255457
--- /dev/null
@@ -0,0 +1,62 @@
+Other patches and addons for OpenSSH. Please send submissions to 
+djm@ibs.com.au
+
+Elsewhere
+---------
+
+http://www.imasy.or.jp/~gotoh/connect.c is a Unix and Windows 
+ProxyCommand which allows OpenSSH to make connections through a SOCKS5
+or http proxy which supports the CONNECT method (eg. Squid).
+
+In this directory
+-----------------
+
+chroot.diff:
+
+Ricardo Cerqueira's <rmcc@clix.pt> patch to enable chrooting using the
+wu-ftpd style magic home directories (containing '/./'). More details in
+the head of the patch itself.
+
+ssh-copy-id:
+
+Phil Hands' <phil@hands.com> shell script to automate the process of adding
+your public key to a remote machine's ~/.ssh/authorized_keys file.
+
+gnome-ssh-askpass:
+
+A GNOME passphrase requester of my own creation. Compilation instructions
+are in the top of the file.
+
+sshd.pam.generic:
+
+A generic PAM config file which may be useful on your system. YMMV
+
+sshd.pam.freebsd:
+
+A PAM config file which works with FreeBSD's PAM port. Contributed by
+Dominik Brettnacher <domi@saargate.de>
+
+mdoc2man.pl:
+
+Converts mdoc formated manpages into normal manpages.  This can be used
+on Solaris machines to provide manpages that are not preformated. 
+Contributed by Mark D. Roth <roth@feep.net>
+
+redhat:
+
+RPM spec file an scripts for building Redhat packages
+
+suse:
+
+RPM spec file an scripts for building SuSE packages
+
+
+Externally maintained
+---------------------
+
+X11 SSH Askpass:
+
+Jim Knoble <jmknoble@pobox.com> has written an excellent X11
+passphrase requester. This is highly recommended:
+
+http://www.ntrnet.net/~jmknoble/software/x11-ssh-askpass/index.html
diff --git a/openssh/contrib/caldera/openssh.spec b/openssh/contrib/caldera/openssh.spec
new file mode 100644 (file)
index 0000000..b11e549
--- /dev/null
@@ -0,0 +1,227 @@
+%define use-stable     1
+%if %{use-stable}
+  %define version      3.0.2p1
+  %define cvs          %{nil}
+  %define release      1
+%else
+  %define version      3.0p1
+  %define cvs          cvs20011102
+  %define release      0r1
+%endif
+%define xsa            x11-ssh-askpass         
+%define askpass                %{xsa}-1.2.4.1
+
+Name           : openssh
+Version        : %{version}%{cvs}
+Release        : %{release}
+Group          : System/Network
+
+Summary        : OpenSSH free Secure Shell (SSH) implementation.
+
+Copyright      : BSD
+Packager       : Raymund Will <ray@caldera.de>
+URL            : http://www.openssh.com/
+
+Obsoletes      : ssh, ssh-clients, openssh-clients
+
+BuildRoot      : /tmp/%{Name}-%{Version}
+
+# %{use-stable}==1:    ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable
+# %{use-stable}==0:    :pserver:cvs@bass.directhit.com:/cvs/openssh_cvs
+Source0: see-above:/.../openssh-%{Version}.tar.gz
+%if %{use-stable}
+Source1: see-above:/.../openssh-%{Version}.tar.gz.sig
+%endif
+Source2: http://www.ntrnet.net/~jmknoble/software/%{xsa}/%{askpass}.tar.gz
+Source3: http://www.openssh.com/faq.html
+
+
+%Package server
+Group          : System/Network
+Requires       : openssh = %{Version}
+Obsoletes      : ssh-server
+
+Summary        : OpenSSH Secure Shell protocol server (sshd).
+
+
+%Package askpass
+Group          : System/Network
+Requires       : openssh = %{Version}
+URL            : http://www.ntrnet.net/~jmknoble/software/x11-ssh-askpass/
+Obsoletes      : ssh-extras
+
+Summary        : OpenSSH X11 pass-phrase dialog.
+
+
+%Prep
+%setup %([ -z "%{cvs}" ] || echo "-n %{Name}_cvs") -a2
+
+%if ! %{use-stable}
+  autoreconf
+%endif
+
+
+%Build
+CFLAGS="$RPM_OPT_FLAGS" \
+./configure \
+            --prefix=/usr \
+            --sysconfdir=/etc/ssh \
+            --libexecdir=/usr/lib/ssh \
+            --with-pam \
+            --with-tcp-wrappers \
+            --with-ipv4-default \
+
+make
+
+cd %{askpass}
+./configure
+xmkmf
+make includes
+make
+
+
+%Install
+%{mkDESTDIR}
+
+make DESTDIR="$DESTDIR" install
+
+make -C %{askpass} BINDIR="/usr/lib/ssh" install
+
+# OpenLinux specific configuration
+mkdir -p $DESTDIR/{etc/pam.d,%{SVIcdir},%{SVIdir}}
+
+# enabling X11 forwarding on the server is convenient and okay,
+# on the client side we consider it a potential security risk!
+%{fixUP} -vT  $DESTDIR/etc/ssh/sshd_config -e '
+   s/X11Forwarding no/X11Forwarding yes/i'
+
+install -m644 contrib/caldera/sshd.pam $DESTDIR/etc/pam.d/sshd
+# FIXME: disabled, find out why this doesn't work with NIS
+%{fixUP} -vT $DESTDIR/etc/pam.d/sshd -e 's/^(.*pam_limits.*)$/#$1/'
+
+install -m 0755 contrib/caldera/sshd.init $DESTDIR%{SVIdir}/sshd
+%{fixUP} -vT $DESTDIR/%{SVIdir} -e 's:\@SVIdir\@:%{SVIdir}: +
+   s:\@sysconfdir\@:/etc/ssh:'
+
+cat <<-EoD > $DESTDIR%{SVIcdir}/sshd
+       IDENT=sshd
+       DESCRIPTIVE="OpenSSH secure shell daemon"
+       # This service will be marked as 'skipped' on boot if there
+       # is no host key. Use ssh-host-keygen to generate one.
+       ONBOOT="yes"
+       OPTIONS=""
+EoD
+
+SKG=$DESTDIR/usr/sbin/ssh-host-keygen
+install -m 0755 contrib/caldera/ssh-host-keygen $SKG
+%{fixUP} -T $SKG -e 's:\@sysconfdir\@:/etc/ssh: +
+   s:\@sshkeygen\@:/usr/bin/ssh-keygen:'
+
+
+# install remaining docs
+DocD="$DESTDIR%{_defaultdocdir}/%{Name}-%{Version}"; mkdir -p $DocD/00-LEGAL
+cp -a LICENCE $DocD/00-LEGAL
+cp -a CREDITS ChangeLog OVERVIEW README* TODO  $DocD
+install -p -m 0444 -o 0 -g 0 %{SOURCE3}  $DocD/faq.html
+mkdir -p $DocD/%{askpass}
+cp -a %{askpass}/{README,ChangeLog,TODO,SshAskpass*.ad}  $DocD/%{askpass}
+
+cp -p %{askpass}/%{xsa}.man $DESTDIR/usr/man/man1/%{xsa}.1
+ln -s  %{xsa}.1 $DESTDIR/usr/man/man1/ssh-askpass.1
+
+%{fixManPages}
+
+
+# generate file lists
+%{mkLists} -c %{Name}
+%{mkLists} -d %{Name} << 'EOF'
+/etc/ssh                               base
+^/etc/                                 IGNORED
+%{_defaultdocdir}/$                    IGNORED
+askpass                                        askpass
+*                                      default
+EOF
+%{mkLists} -a -f %{Name} << 'EOF'
+^/etc                                  *               prefix(%%config)
+/usr/X11R6/lib/X11/app-defaults        IGNORED
+Ssh.bin                                IGNORED         # for now
+[Aa]skpass                             askpass
+%{_defaultdocdir}/%{Name}-%{Version}/  base
+ssh-keygen                             base
+moduli                                 server
+sshd                                   server
+sftp-server                            server
+.*                                     base
+EOF
+
+
+%Clean
+%{rmDESTDIR}
+
+
+%Post
+# Generate host key when none is present to get up and running,
+# both client and server require this for host-based auth!
+# ssh-host-keygen checks for existing keys.
+/usr/sbin/ssh-host-keygen
+: # to protect the rpm database
+
+
+%Post server
+if [ -x %{LSBinit}-install ]; then
+  %{LSBinit}-install sshd
+else
+  lisa --SysV-init install sshd S55 3:4:5 K45 0:1:2:6
+fi
+
+! %{SVIdir}/sshd status || %{SVIdir}/sshd restart
+: # to protect the rpm database
+
+
+%PreUn server
+[ "$1" = 0 ] || exit 0
+
+! %{SVIdir}/sshd status || %{SVIdir}/sshd stop
+: # to protect the rpm database
+
+
+%PostUn server
+if [ -x %{LSBinit}-remove ]; then
+  %{LSBinit}-remove sshd
+else
+  lisa --SysV-init remove sshd $1
+fi
+: # to protect the rpm database
+
+
+%Files -f files-%{Name}-base
+%defattr(-,root,root)
+
+
+%Files server -f files-%{Name}-server
+%defattr(-,root,root)
+
+
+%Files askpass -f files-%{Name}-askpass
+%defattr(-,root,root)
+
+
+%Description
+OpenSSH (Secure Shell) provides access to a remote system. It replaces
+telnet, rlogin,  rexec, and rsh, and 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.
+
+%Description server
+This package installs the sshd, the server portion of OpenSSH. 
+
+%Description askpass
+This package contains an X11-based pass-phrase dialog used per
+default by ssh-add(1). It is based on %{askpass}
+by Jim Knoble <jmknoble@pobox.com>.
+
+%ChangeLog
+* Mon Jan 01 1998 ...
+
+$Id$
diff --git a/openssh/contrib/caldera/ssh-host-keygen b/openssh/contrib/caldera/ssh-host-keygen
new file mode 100755 (executable)
index 0000000..94e3997
--- /dev/null
@@ -0,0 +1,36 @@
+#! /bin/sh
+#
+# $Id$
+#
+# This script is normally run only *once* for a given host
+# (in a given period of time) -- on updates/upgrades/recovery
+# the ssh_host_key* files _should_ be retained! Otherwise false
+# "man-in-the-middle-attack" alerts will frighten unsuspecting
+# clients...
+
+keydir=@sysconfdir@
+keygen=@sshkeygen@
+
+if [ -f $keydir/ssh_host_key -o \
+             -f $keydir/ssh_host_key.pub ]; then
+  echo "You already have an SSH1 RSA host key in $keydir/ssh_host_key."
+else
+  echo "Generating 1024 bit SSH1 RSA host key."
+  $keygen -b 1024 -t rsa1 -f $keydir/ssh_host_key -C '' -N ''
+fi
+
+if [ -f $keydir/ssh_host_rsa_key -o \
+             -f $keydir/ssh_host_rsa_key.pub ]; then
+  echo "You already have an SSH2 RSA host key in $keydir/ssh_host_rsa_key."
+else
+  echo "Generating 1024 bit SSH2 RSA host key."
+  $keygen -b 1024 -t rsa -f $keydir/ssh_host_rsa_key -C '' -N ''
+fi
+
+if [ -f $keydir/ssh_host_dsa_key -o \
+             -f $keydir/ssh_host_dsa_key.pub ]; then
+  echo "You already have an SSH2 DSA host key in $keydir/ssh_host_dsa_key."
+else
+  echo "Generating SSH2 DSA host key."
+  $keygen -t dsa -f $keydir/ssh_host_dsa_key -C '' -N ''
+fi
diff --git a/openssh/contrib/caldera/sshd.init b/openssh/contrib/caldera/sshd.init
new file mode 100755 (executable)
index 0000000..bb0c9f9
--- /dev/null
@@ -0,0 +1,125 @@
+#! /bin/bash
+#
+# $Id$
+#
+### BEGIN INIT INFO
+# Provides:
+# Required-Start: $network
+# Required-Stop:
+# Default-Start:  3 4 5
+# Default-Stop:   0 1 2 6
+# Description: sshd
+#                Bring up/down the OpenSSH secure shell daemon.
+### END INIT INFO
+#
+# Written by Miquel van Smoorenburg <miquels@drinkel.ow.org>.
+# Modified for Debian GNU/Linux by Ian Murdock <imurdock@gnu.ai.mit.edu>.
+# Modified for OpenLinux by Raymund Will <ray@caldera.de>
+
+NAME=sshd
+DAEMON=/usr/sbin/$NAME
+# Hack-Alert(TM)!  This is necessary to get around the 'reload'-problem
+# created by recent OpenSSH daemon/ssd combinations. See Caldera internal
+# PR [linux/8278] for details...
+PIDF=/var/run/$NAME.pid
+NAME=$DAEMON
+
+_status() {
+  [ -z "$1" ] || local pidf="$1"
+  local ret=-1
+  local pid
+  if [ -n "$pidf" ] && [  -r "$pidf" ]; then
+    pid=$(head -1 $pidf)
+  else
+    pid=$(pidof $NAME)
+  fi
+
+  if [ ! -e $SVIlock ]; then
+    # no lock-file => not started == stopped?
+    ret=3
+  elif [ -n "$pidf" -a ! -f "$pidf" ] || [ -z "$pid" ]; then
+    # pid-file given but not present or no pid => died, but was not stopped
+    ret=2
+  elif [ -r /proc/$pid/cmdline ] &&
+       echo -ne $NAME'\000' | cmp -s - /proc/$pid/cmdline; then
+    # pid-file given and present or pid found => check process...
+    # but don't compare exe, as this will fail after an update!
+    # compares OK => all's well, that ends well...
+    ret=0
+  else
+    # no such process or exe does not match => stale pid-file or process died
+    #   just recently...
+    ret=1
+  fi
+  return $ret
+}
+
+# Source function library (and set vital variables).
+. @SVIdir@/functions
+
+case "$1" in
+ start)
+  [ ! -e $SVIlock ] || exit 0
+  [ -x $DAEMON ] || exit 5
+  SVIemptyConfig @sysconfdir@/sshd_config && exit 6
+
+  if [ ! \( -f @sysconfdir@/ssh_host_key -a            \
+            -f @sysconfdir@/ssh_host_key.pub \) -a     \
+       ! \( -f @sysconfdir@/ssh_host_rsa_key -a        \
+            -f @sysconfdir@/ssh_host_rsa_key.pub \) -a \
+       ! \( -f @sysconfdir@/ssh_host_dsa_key -a        \
+            -f @sysconfdir@/ssh_host_dsa_key.pub \) ]; then
+
+    echo "$SVIsubsys: host key not initialized: skipped!"
+    echo "$SVIsubsys: use ssh-host-keygen to generate one!"
+    exit 6
+  fi
+
+  echo -n "Starting $SVIsubsys services: "
+  ssd -S -x $DAEMON -n $NAME -- $OPTIONS
+  ret=$?
+
+  echo  "."
+  touch $SVIlock
+  ;;
+
+ stop)
+  [ -e $SVIlock ] || exit 0
+
+  echo -n "Stopping $SVIsubsys services: "
+  ssd -K -p $PIDF -n $NAME
+  ret=$?
+
+  echo "."
+  rm -f $SVIlock
+  ;;
+
+ force-reload|reload)
+  [ -e $SVIlock ] || exit 0
+
+  echo "Reloading $SVIsubsys configuration files: "
+  ssd -K --signal 1 -q -p $PIDF -n $NAME
+  ret=$?
+  echo "done."
+  ;;
+
+ restart)
+  $0 stop
+  $0 start
+  ret=$?
+  ;;
+
+ status)
+  _status $PIDF
+  ret=$?
+  ;;
+
+ *)
+  echo "Usage: $SVIscript {[re]start|stop|[force-]reload|status}"
+  ret=2
+  ;;
+
+esac
+
+exit $ret
+
diff --git a/openssh/contrib/caldera/sshd.pam b/openssh/contrib/caldera/sshd.pam
new file mode 100644 (file)
index 0000000..26dcb34
--- /dev/null
@@ -0,0 +1,8 @@
+#%PAM-1.0
+auth       required     /lib/security/pam_pwdb.so shadow nodelay
+auth       required     /lib/security/pam_nologin.so
+account    required     /lib/security/pam_pwdb.so
+password   required     /lib/security/pam_cracklib.so
+password   required     /lib/security/pam_pwdb.so shadow nullok use_authtok
+session    required     /lib/security/pam_pwdb.so
+session    required     /lib/security/pam_limits.so
diff --git a/openssh/contrib/chroot.diff b/openssh/contrib/chroot.diff
new file mode 100644 (file)
index 0000000..d2a42d8
--- /dev/null
@@ -0,0 +1,61 @@
+From: Ricardo Cerqueira <rmcc@clix.pt>
+
+A patch to cause sshd to chroot when it encounters the magic token
+'/./' in a users home directory. The directory portion before the
+token is the directory to chroot() to, the portion after the
+token is the user's home directory relative to the new root.
+
+Index: session.c
+===================================================================
+RCS file: /var/cvs/openssh/session.c,v
+retrieving revision 1.4
+diff -u -r1.4 session.c
+--- session.c  2000/04/16 02:31:51     1.4
++++ session.c  2000/04/16 02:47:55
+@@ -27,6 +27,8 @@
+ #include "ssh2.h"
+ #include "auth.h"
++#define CHROOT
++
+ /* types */
+ #define TTYSZ 64
+@@ -783,6 +785,10 @@
+       extern char **environ;
+       struct stat st;
+       char *argv[10];
++#ifdef CHROOT
++      char *user_dir;
++      char *new_root;
++#endif /* CHROOT */
+ #ifndef USE_PAM /* pam_nologin handles this */
+       f = fopen("/etc/nologin", "r");
+@@ -799,6 +805,26 @@
+       /* Set login name in the kernel. */
+       if (setlogin(pw->pw_name) < 0)
+               error("setlogin failed: %s", strerror(errno));
++
++#ifdef CHROOT
++      user_dir = xstrdup(pw->pw_dir);
++      new_root = user_dir + 1;                                                                                  
++
++      while((new_root = strchr(new_root, '.')) != NULL) {
++              new_root--;
++              if(strncmp(new_root, "/./", 3) == 0) {
++                      *new_root = '\0';
++                      new_root += 2;
++
++                      if(chroot(user_dir) != 0)
++                              fatal("Couldn't chroot to user directory %s", user_dir);
++
++                      pw->pw_dir = new_root;
++                      break;
++              }
++              new_root += 2;
++      }
++#endif /* CHROOT */
+       /* Set uid, gid, and groups. */
+       /* Login(1) does this as well, and it needs uid 0 for the "-h"
diff --git a/openssh/contrib/cygwin/README b/openssh/contrib/cygwin/README
new file mode 100644 (file)
index 0000000..dfe1786
--- /dev/null
@@ -0,0 +1,178 @@
+This package is the actual port of OpenSSH to Cygwin 1.3.
+
+===========================================================================
+Important change since 2.9p2:
+
+Since Cygwin is able to switch user context without password beginning
+with version 1.3.2, OpenSSH now allows to do so when it's running under
+a version >= 1.3.2. Keep in mind that `ntsec' has to be activated to
+allow that feature.
+===========================================================================
+
+===========================================================================
+Important change since 2.3.0p1:
+
+When using `ntea' or `ntsec' you now have to care for the ownership
+and permission bits of your host key files and your private key files.
+The host key files have to be owned by the NT account which starts
+sshd. The user key files have to be owned by the user. The permission
+bits of the private key files (host and user) have to be at least
+rw------- (0600)!
+
+Note that this is forced under `ntsec' only if the files are on a NTFS
+filesystem (which is recommended) due to the lack of any basic security
+features of the FAT/FAT32 filesystems.
+===========================================================================
+
+If you are installing OpenSSH the first time, you can generate global config
+files and server keys by running
+   
+   /usr/bin/ssh-host-config
+
+Note that this binary archive doesn't contain default config files in /etc.
+That files are only created if ssh-host-config is started.
+
+If you are updating your installation you may run the above ssh-host-config
+as well to move your configuration files to the new location and to
+erase the files at the old location.
+
+To support testing and unattended installation ssh-host-config got
+some options:
+
+usage: ssh-host-config [OPTION]...
+Options:
+    --debug      -d        Enable shell's debug output.
+    --yes        -y        Answer all questions with "yes" automatically.
+    --no         -n        Answer all questions with "no" automatically.
+    --port       -p <n>    sshd listens on port n.
+
+Additionally ssh-host-config now asks if it should install sshd as a
+service when running under NT/W2K. This requires cygrunsrv installed.
+
+You can create the private and public keys for a user now by running
+
+  /usr/bin/ssh-user-config
+
+under the users account.
+
+To support testing and unattended installation ssh-user-config got
+some options as well:
+
+usage: ssh-user-config [OPTION]...
+Options:
+    --debug      -d        Enable shell's debug output.
+    --yes        -y        Answer all questions with "yes" automatically.
+    --no         -n        Answer all questions with "no" automatically.
+    --passphrase -p word   Use "word" as passphrase automatically.
+
+Install sshd as daemon via cygrunsrv.exe (recommended on NT/W2K), via inetd
+(results in very slow deamon startup!) or from the command line (recommended
+on 9X/ME).
+
+If you start sshd as deamon via cygrunsrv.exe you MUST give the
+"-D" option to sshd. Otherwise the service can't get started at all.
+
+If starting via inetd, copy sshd to eg. /usr/sbin/in.sshd and add the
+following line to your inetd.conf file:
+
+sshd stream tcp nowait root /usr/sbin/in.sshd sshd -i
+
+Moreover you'll have to add the following line to your
+${SYSTEMROOT}/system32/drivers/etc/services file:
+
+   sshd         22/tcp          #SSH daemon
+
+===========================================================================
+The following restrictions only apply to Cygwin versions up to 1.3.1
+===========================================================================
+
+Authentication to sshd is possible in one of two ways.
+You'll have to decide before starting sshd!
+
+- If you want to authenticate via RSA and you want to login to that
+  machine to exactly one user account you can do so by running sshd
+  under that user account. You must change /etc/sshd_config
+  to contain the following:
+
+  RSAAuthentication yes
+
+  Moreover it's possible to use rhosts and/or rhosts with
+  RSA authentication by setting the following in sshd_config:
+
+  RhostsAuthentication yes
+  RhostsRSAAuthentication yes
+
+- If you want to be able to login to different user accounts you'll
+  have to start sshd under system account or any other account that
+  is able to switch user context. Note that administrators are _not_
+  able to do that by default! You'll have to give the following
+  special user rights to the user:
+  "Act as part of the operating system"
+  "Replace process level token"
+  "Increase quotas"
+  and if used via service manager
+  "Logon as a service".
+
+  The system account does of course own that user rights by default.
+
+  Unfortunately, if you choose that way, you can only logon with
+  NT password authentification and you should change
+  /etc/sshd_config to contain the following:
+
+    PasswordAuthentication yes
+    RhostsAuthentication no
+    RhostsRSAAuthentication no
+    RSAAuthentication no
+
+  However you can login to the user which has started sshd with
+  RSA authentication anyway. If you want that, change the RSA
+  authentication setting back to "yes":
+     
+    RSAAuthentication yes
+
+Please note that OpenSSH does never use the value of $HOME to
+search for the users configuration files! It always uses the
+value of the pw_dir field in /etc/passwd as the home directory.
+If no home diretory is set in /etc/passwd, the root directory
+is used instead!
+
+You may use all features of the CYGWIN=ntsec setting the same
+way as they are used by the `login' port on sources.redhat.com:
+
+  The pw_gecos field may contain an additional field, that begins
+  with (upper case!) "U-", followed by the domain and the username
+  separated by a backslash.
+  CAUTION: The SID _must_ remain the _last_ field in pw_gecos!
+  BTW: The field separator in pw_gecos is the comma.
+  The username in pw_name itself may be any nice name:
+
+    domuser::1104:513:John Doe,U-domain\user,S-1-5-21-...
+
+  Now you may use `domuser' as your login name with telnet!
+  This is possible additionally for local users, if you don't like
+  your NT login name ;-) You only have to leave out the domain:
+
+    locuser::1104:513:John Doe,U-user,S-1-5-21-...
+
+SSH2 server and user keys are generated by the `ssh-*-config' scripts
+as well.
+
+If you want to build from source, the following options to
+configure are used for the Cygwin binary distribution:
+
+       --prefix=/usr \
+       --sysconfdir=/etc \
+       --libexecdir='${exec_prefix}/sbin \
+       --with-pcre
+
+You must have installed the zlib, openssl and regex packages to
+be able to build OpenSSH! The `--with-pcre' option requires
+the installation of the pcre package.
+
+Please send requests, error reports etc. to cygwin@cygwin.com.
+
+Have fun,
+
+Corinna Vinschen <vinschen@redhat.com>
+Cygwin Developer
+Red Hat Inc.
diff --git a/openssh/contrib/cygwin/ssh-host-config b/openssh/contrib/cygwin/ssh-host-config
new file mode 100644 (file)
index 0000000..bfeee7f
--- /dev/null
@@ -0,0 +1,495 @@
+#!/bin/sh
+#
+# ssh-host-config, Copyright 2000, Red Hat Inc.
+#
+# This file is part of the Cygwin port of OpenSSH.
+
+# Subdirectory where the new package is being installed
+PREFIX=/usr
+
+# Directory where the config files are stored
+SYSCONFDIR=/etc
+
+# Subdirectory where an old package might be installed
+OLDPREFIX=/usr/local
+OLDSYSCONFDIR=${OLDPREFIX}/etc
+
+progname=$0
+auto_answer=""
+port_number=22
+
+request()
+{
+  if [ "${auto_answer}" = "yes" ]
+  then
+    return 0
+  elif [ "${auto_answer}" = "no" ]
+  then
+    return 1
+  fi
+
+  answer=""
+  while [ "X${answer}" != "Xyes" -a "X${answer}" != "Xno" ]
+  do
+    echo -n "$1 (yes/no) "
+    read answer
+  done
+  if [ "X${answer}" = "Xyes" ]
+  then
+    return 0
+  else
+    return 1
+  fi
+}
+
+# Check options
+
+while :
+do
+  case $# in
+  0)
+    break
+    ;;
+  esac
+
+  option=$1
+  shift
+
+  case "$option" in
+  -d | --debug )
+    set -x
+    ;;
+
+  -y | --yes )
+    auto_answer=yes
+    ;;
+
+  -n | --no )
+    auto_answer=no
+    ;;
+
+  -p | --port )
+    port_number=$1
+    shift
+    ;;
+
+  *)
+    echo "usage: ${progname} [OPTION]..."
+    echo
+    echo "This script creates an OpenSSH host configuration."
+    echo
+    echo "Options:"
+    echo "    --debug  -d     Enable shell's debug output."
+    echo "    --yes    -y     Answer all questions with \"yes\" automatically."
+    echo "    --no     -n     Answer all questions with \"no\" automatically."
+    echo "    --port   -p <n> sshd listens on port n."
+    echo
+    exit 1
+    ;;
+
+  esac
+done
+
+# Check for running ssh/sshd processes first. Refuse to do anything while
+# some ssh processes are still running
+
+if ps -ef | grep -v grep | grep -q ssh
+then
+  echo
+  echo "There are still ssh processes running. Please shut them down first."
+  echo
+  #exit 1
+fi
+
+# Check for ${SYSCONFDIR} directory
+
+if [ -e "${SYSCONFDIR}" -a ! -d "${SYSCONFDIR}" ]
+then
+  echo
+  echo "${SYSCONFDIR} is existant but not a directory."
+  echo "Cannot create global configuration files."
+  echo
+  exit 1
+fi
+
+# Create it if necessary
+
+if [ ! -e "${SYSCONFDIR}" ]
+then
+  mkdir "${SYSCONFDIR}"
+  if [ ! -e "${SYSCONFDIR}" ]
+  then
+    echo
+    echo "Creating ${SYSCONFDIR} directory failed"
+    echo
+    exit 1
+  fi
+fi
+
+# Check for an old installation in ${OLDPREFIX} unless ${OLDPREFIX} isn't
+# the same as ${PREFIX}
+
+old_install=0
+if [ "${OLDPREFIX}" != "${PREFIX}" ]
+then
+  if [ -f "${OLDPREFIX}/sbin/sshd" ]
+  then
+    echo
+    echo "You seem to have an older installation in ${OLDPREFIX}."
+    echo
+    # Check if old global configuration files exist
+    if [ -f "${OLDSYSCONFDIR}/ssh_host_key" ]
+    then
+      if request "Do you want to copy your config files to your new installation?"
+      then
+        cp -f ${OLDSYSCONFDIR}/ssh_host_key ${SYSCONFDIR}
+        cp -f ${OLDSYSCONFDIR}/ssh_host_key.pub ${SYSCONFDIR}
+        cp -f ${OLDSYSCONFDIR}/ssh_host_dsa_key ${SYSCONFDIR}
+        cp -f ${OLDSYSCONFDIR}/ssh_host_dsa_key.pub ${SYSCONFDIR}
+        cp -f ${OLDSYSCONFDIR}/ssh_config ${SYSCONFDIR}
+        cp -f ${OLDSYSCONFDIR}/sshd_config ${SYSCONFDIR}
+      fi
+    fi
+    if request "Do you want to erase your old installation?"
+    then
+      rm -f ${OLDPREFIX}/bin/ssh.exe
+      rm -f ${OLDPREFIX}/bin/ssh-config
+      rm -f ${OLDPREFIX}/bin/scp.exe
+      rm -f ${OLDPREFIX}/bin/ssh-add.exe
+      rm -f ${OLDPREFIX}/bin/ssh-agent.exe
+      rm -f ${OLDPREFIX}/bin/ssh-keygen.exe
+      rm -f ${OLDPREFIX}/bin/slogin
+      rm -f ${OLDSYSCONFDIR}/ssh_host_key
+      rm -f ${OLDSYSCONFDIR}/ssh_host_key.pub
+      rm -f ${OLDSYSCONFDIR}/ssh_host_dsa_key
+      rm -f ${OLDSYSCONFDIR}/ssh_host_dsa_key.pub
+      rm -f ${OLDSYSCONFDIR}/ssh_config
+      rm -f ${OLDSYSCONFDIR}/sshd_config
+      rm -f ${OLDPREFIX}/man/man1/ssh.1
+      rm -f ${OLDPREFIX}/man/man1/scp.1
+      rm -f ${OLDPREFIX}/man/man1/ssh-add.1
+      rm -f ${OLDPREFIX}/man/man1/ssh-agent.1
+      rm -f ${OLDPREFIX}/man/man1/ssh-keygen.1
+      rm -f ${OLDPREFIX}/man/man1/slogin.1
+      rm -f ${OLDPREFIX}/man/man8/sshd.8
+      rm -f ${OLDPREFIX}/sbin/sshd.exe
+      rm -f ${OLDPREFIX}/sbin/sftp-server.exe
+    fi
+    old_install=1
+  fi
+fi
+
+# First generate host keys if not already existing
+
+if [ ! -f "${SYSCONFDIR}/ssh_host_key" ]
+then
+  echo "Generating ${SYSCONFDIR}/ssh_host_key"
+  ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null
+fi
+
+if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ]
+then
+  echo "Generating ${SYSCONFDIR}/ssh_host_rsa_key"
+  ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null
+fi
+
+if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ]
+then
+  echo "Generating ${SYSCONFDIR}/ssh_host_dsa_key"
+  ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null
+fi
+
+# Check if ssh_config exists. If yes, ask for overwriting
+
+if [ -f "${SYSCONFDIR}/ssh_config" ]
+then
+  if request "Overwrite existing ${SYSCONFDIR}/ssh_config file?"
+  then
+    rm -f "${SYSCONFDIR}/ssh_config"
+    if [ -f "${SYSCONFDIR}/ssh_config" ]
+    then
+      echo "Can't overwrite. ${SYSCONFDIR}/ssh_config is write protected."
+    fi
+  fi
+fi
+
+# Create default ssh_config from here script
+
+if [ ! -f "${SYSCONFDIR}/ssh_config" ]
+then
+  echo "Generating ${SYSCONFDIR}/ssh_config file"
+  cat > ${SYSCONFDIR}/ssh_config << EOF
+# This is ssh client systemwide configuration file.  This file provides 
+# defaults for users, and the values can be changed in per-user configuration
+# files or on the command line.
+
+# Configuration data is parsed as follows:
+#  1. command line options
+#  2. user-specific file
+#  3. system-wide file
+# Any configuration value is only changed the first time it is set.
+# Thus, host-specific definitions should be at the beginning of the
+# configuration file, and defaults at the end.
+
+# Site-wide defaults for various options
+
+# Host *
+#   ForwardAgent no
+#   ForwardX11 no
+#   RhostsAuthentication no
+#   RhostsRSAAuthentication yes
+#   RSAAuthentication yes
+#   PasswordAuthentication yes
+#   FallBackToRsh no
+#   UseRsh no
+#   BatchMode no
+#   CheckHostIP yes
+#   StrictHostKeyChecking yes
+#   IdentityFile ~/.ssh/identity
+#   IdentityFile ~/.ssh/id_dsa
+#   IdentityFile ~/.ssh/id_rsa
+#   Port 22
+#   Protocol 2,1
+#   Cipher blowfish
+#   EscapeChar ~
+EOF
+  if [ "$port_number" != "22" ]
+  then
+    echo "Host localhost" >> ${SYSCONFDIR}/ssh_config
+    echo "    Port $port_number" >> ${SYSCONFDIR}/ssh_config
+  fi
+fi
+
+# Check if sshd_config exists. If yes, ask for overwriting
+
+if [ -f "${SYSCONFDIR}/sshd_config" ]
+then
+  if request "Overwrite existing ${SYSCONFDIR}/sshd_config file?"
+  then
+    rm -f "${SYSCONFDIR}/sshd_config"
+    if [ -f "${SYSCONFDIR}/sshd_config" ]
+    then
+      echo "Can't overwrite. ${SYSCONFDIR}/sshd_config is write protected."
+    fi
+  fi
+fi
+
+# Create default sshd_config from here script
+
+if [ ! -f "${SYSCONFDIR}/sshd_config" ]
+then
+  echo "Generating ${SYSCONFDIR}/sshd_config file"
+  cat > ${SYSCONFDIR}/sshd_config << EOF
+# This is the sshd server system-wide configuration file.  See sshd(8)
+# for more information.
+
+Port $port_number
+#Protocol 2,1
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# HostKey for protocol version 1
+HostKey /etc/ssh_host_key
+# HostKeys for protocol version 2
+HostKey /etc/ssh_host_rsa_key
+HostKey /etc/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server ke
+KeyRegenerationInterval 3600
+ServerKeyBits 768
+
+# Logging
+SyslogFacility AUTH
+LogLevel INFO
+#obsoletes QuietMode and FascistLogging
+
+# Authentication:
+
+LoginGraceTime 600
+PermitRootLogin yes
+# The following setting overrides permission checks on host key files
+# and directories. For security reasons set this to "yes" when running
+# NT/W2K, NTFS and CYGWIN=ntsec.
+StrictModes no
+
+RSAAuthentication yes
+PubkeyAuthentication yes
+#AuthorizedKeysFile     %h/.ssh/authorized_keys
+
+# rhosts authentication should not be used
+RhostsAuthentication no
+# Don't read ~/.rhosts and ~/.shosts files
+IgnoreRhosts yes
+# For this to work you will also need host keys in /etc/ssh_known_hosts
+RhostsRSAAuthentication no
+# similar for protocol version 2
+HostbasedAuthentication no
+# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
+#IgnoreUserKnownHosts yes
+
+# To disable tunneled clear text passwords, change to no here!
+PasswordAuthentication yes
+PermitEmptyPasswords no
+
+X11Forwarding no
+X11DisplayOffset 10
+PrintMotd yes
+#PrintLastLog no
+KeepAlive yes
+#UseLogin no
+
+#MaxStartups 10:30:60
+#Banner /etc/issue.net
+#ReverseMappingCheck yes
+
+Subsystem      sftp    /usr/sbin/sftp-server
+EOF
+fi
+
+# Care for services file
+_sys="`uname -a`"
+_nt=`expr "$_sys" : "CYGWIN_NT"`
+if [ $_nt -gt 0 ]
+then
+  _wservices="${SYSTEMROOT}\\system32\\drivers\\etc\\services"
+  _wserv_tmp="${SYSTEMROOT}\\system32\\drivers\\etc\\srv.out.$$"
+else
+  _wservices="${WINDIR}\\SERVICES"
+  _wserv_tmp="${WINDIR}\\SERV.$$"
+fi
+_services=`cygpath -u "${_wservices}"`
+_serv_tmp=`cygpath -u "${_wserv_tmp}"`
+
+mount -t -f "${_wservices}" "${_services}"
+mount -t -f "${_wserv_tmp}" "${_serv_tmp}"
+
+# Remove sshd 22/port from services
+if [ `grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
+then
+  grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
+  if [ -f "${_serv_tmp}" ]
+  then 
+    if mv "${_serv_tmp}" "${_services}"
+    then
+      echo "Removing sshd from ${_services}"
+    else
+      echo "Removing sshd from ${_services} failed\!"
+    fi 
+    rm -f "${_serv_tmp}"
+  else
+    echo "Removing sshd from ${_services} failed\!"
+  fi
+fi
+
+# Add ssh 22/tcp  and ssh 22/udp to services
+if [ `grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ]
+then
+  awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh                22/tcp                           #SSH Remote Login Protocol\nssh                22/udp                           #SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}"
+  if [ -f "${_serv_tmp}" ]
+  then
+    if mv "${_serv_tmp}" "${_services}"
+    then
+      echo "Added ssh to ${_services}"
+    else
+      echo "Adding ssh to ${_services} failed\!"
+    fi
+    rm -f "${_serv_tmp}"
+  else
+    echo "Adding ssh to ${_services} failed\!"
+  fi
+fi
+
+umount "${_services}"
+umount "${_serv_tmp}"
+
+# Care for inetd.conf file
+_inetcnf="/etc/inetd.conf"
+_inetcnf_tmp="/etc/inetd.conf.$$"
+
+if [ -f "${_inetcnf}" ]
+then
+  # Check if ssh service is already in use as sshd
+  with_comment=1
+  grep -q '^[ \t]*sshd' "${_inetcnf}" && with_comment=0
+  # Remove sshd line from inetd.conf
+  if [ `grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
+  then
+    grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
+    if [ -f "${_inetcnf_tmp}" ]
+    then
+      if mv "${_inetcnf_tmp}" "${_inetcnf}"
+      then
+        echo "Removed sshd from ${_inetcnf}"
+      else
+        echo "Removing sshd from ${_inetcnf} failed\!"
+      fi
+      rm -f "${_inetcnf_tmp}"
+    else
+      echo "Removing sshd from ${_inetcnf} failed\!"
+    fi
+  fi
+
+  # Add ssh line to inetd.conf
+  if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -ne 0 ]
+  then
+    if [ "${with_comment}" -eq 0 ]
+    then
+      echo 'ssh  stream  tcp     nowait  root    /usr/sbin/sshd -i' >> "${_inetcnf}"
+    else
+      echo '# ssh  stream  tcp     nowait  root    /usr/sbin/sshd -i' >> "${_inetcnf}"
+    fi
+    echo "Added ssh to ${_inetcnf}"
+  fi
+fi
+
+# Create /var/log and /var/log/lastlog if not already existing
+
+if [ -f /var/log ]
+then
+  echo "Creating /var/log failed\!"
+else
+  if [ ! -d /var/log ]
+  then
+    mkdir /var/log
+  fi
+  if [ -d /var/log/lastlog ]
+  then
+    echo "Creating /var/log/lastlog failed\!"
+  elif [ ! -f /var/log/lastlog ]
+  then
+    cat /dev/null > /var/log/lastlog
+  fi
+fi
+
+# On NT ask if sshd should be installed as service
+if [ $_nt -gt 0 ]
+then
+  echo
+  echo "Do you want to install sshd as service?"
+  if request "(Say \"no\" if it's already installed as service)"
+  then
+    echo
+    echo "Which value should the environment variable CYGWIN have when"
+    echo "sshd starts? It's recommended to set at least \"ntsec\" to be"
+    echo "able to change user context without password."
+    echo -n "Default is \"binmode ntsec tty\".  CYGWIN="
+    read _cygwin
+    [ -z "${_cygwin}" ] && _cygwin="binmode ntsec tty"
+    if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a -D -e "CYGWIN=${_cygwin}"
+    then
+      chown system /etc/ssh*
+      echo
+      echo "The service has been installed under LocalSystem account."
+    fi
+  fi
+fi
+
+if [ "${old_install}" = "1" ]
+then
+  echo
+  echo "Note: If you have used sshd as service or from inetd, don't forget to"
+  echo "      change the path to sshd.exe in the service entry or in inetd.conf."
+fi
+
+echo
+echo "Host configuration finished. Have fun!"
diff --git a/openssh/contrib/cygwin/ssh-user-config b/openssh/contrib/cygwin/ssh-user-config
new file mode 100644 (file)
index 0000000..5a76adb
--- /dev/null
@@ -0,0 +1,200 @@
+#!/bin/sh
+#
+# ssh-user-config, Copyright 2000, Red Hat Inc.
+#
+# This file is part of the Cygwin port of OpenSSH.
+
+progname=$0
+auto_answer=""
+auto_passphrase="no"
+passphrase=""
+
+request()
+{
+  if [ "${auto_answer}" = "yes" ]
+  then
+    return 0
+  elif [ "${auto_answer}" = "no" ]
+  then
+    return 1
+  fi
+
+  answer=""
+  while [ "X${answer}" != "Xyes" -a "X${answer}" != "Xno" ]
+  do
+    echo -n "$1 (yes/no) "
+    read answer
+  done
+  if [ "X${answer}" = "Xyes" ]
+  then
+    return 0
+  else
+    return 1
+  fi
+}
+
+# Check options
+
+while :
+do
+  case $# in
+  0)
+    break
+    ;;
+  esac
+
+  option=$1
+  shift
+
+  case "$option" in
+  -d | --debug )
+    set -x
+    ;;
+
+  -y | --yes )
+    auto_answer=yes
+    ;;
+
+  -n | --no )
+    auto_answer=no
+    ;;
+
+  -p | --passphrase )
+    with_passphrase="yes"
+    passphrase=$1
+    shift
+    ;;
+
+  *)
+    echo "usage: ${progname} [OPTION]..."
+    echo
+    echo "This script creates an OpenSSH user configuration."
+    echo
+    echo "Options:"
+    echo "    --debug      -d        Enable shell's debug output."
+    echo "    --yes        -y        Answer all questions with \"yes\" automatically."
+    echo "    --no         -n        Answer all questions with \"no\" automatically."
+    echo "    --passphrase -p word   Use \"word\" as passphrase automatically."
+    echo
+    exit 1
+    ;;
+
+  esac
+done
+
+# Ask user if user identity should be generated
+
+if [ ! -f /etc/passwd ]
+then
+  echo '/etc/passwd is nonexistant. Please generate an /etc/passwd file'
+  echo 'first using mkpasswd. Check if it contains an entry for you and'
+  echo 'please care for the home directory in your entry as well.'
+  exit 1
+fi
+
+uid=`id -u`
+pwdhome=`awk -F: '{ if ( $3 == '${uid}' ) print $6; }' < /etc/passwd`
+
+if [ "X${pwdhome}" = "X" ]
+then
+  echo 'There is no home directory set for you in /etc/passwd.'
+  echo 'Setting $HOME is not sufficient!'
+  exit 1
+fi
+
+if [ ! -d "${pwdhome}" ]
+then
+  echo "${pwdhome} is set in /etc/passwd as your home directory"
+  echo 'but it is not a valid directory. Cannot create user identity files.'
+  exit 1
+fi
+
+# If home is the root dir, set home to empty string to avoid error messages
+# in subsequent parts of that script.
+if [ "X${pwdhome}" = "X/" ]
+then
+  # But first raise a warning!
+  echo 'Your home directory in /etc/passwd is set to root (/). This is not recommended!'
+  if request "Would you like to proceed anyway?"
+  then
+    pwdhome=''
+  else
+    exit 1
+  fi
+fi
+
+if [ -e "${pwdhome}/.ssh" -a ! -d "${pwdhome}/.ssh" ]
+then
+  echo "${pwdhome}/.ssh is existant but not a directory. Cannot create user identity files."
+  exit 1
+fi
+
+if [ ! -e "${pwdhome}/.ssh" ]
+then
+  mkdir "${pwdhome}/.ssh"
+  if [ ! -e "${pwdhome}/.ssh" ]
+  then
+    echo "Creating users ${pwdhome}/.ssh directory failed"
+    exit 1
+  fi
+fi
+
+if [ ! -f "${pwdhome}/.ssh/identity" ]
+then
+  if request "Shall I create an SSH1 RSA identity file for you?"
+  then
+    echo "Generating ${pwdhome}/.ssh/identity"
+    if [ "${with_passphrase}" = "yes" ]
+    then
+      ssh-keygen -t rsa1 -N "${passphrase}" -f "${pwdhome}/.ssh/identity" > /dev/null
+    else
+      ssh-keygen -t rsa1 -f "${pwdhome}/.ssh/identity" > /dev/null
+    fi
+    if request "Do you want to use this identity to login to this machine?"
+    then
+      echo "Adding to ${pwdhome}/.ssh/authorized_keys"
+      cat "${pwdhome}/.ssh/identity.pub" >> "${pwdhome}/.ssh/authorized_keys"
+    fi
+  fi
+fi
+
+if [ ! -f "${pwdhome}/.ssh/id_rsa" ]
+then
+  if request "Shall I create an SSH2 RSA identity file for you? (yes/no) "
+  then
+    echo "Generating ${pwdhome}/.ssh/id_rsa"
+    if [ "${with_passphrase}" = "yes" ]
+    then
+      ssh-keygen -t rsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_rsa" > /dev/null
+    else
+      ssh-keygen -t rsa -f "${pwdhome}/.ssh/id_rsa" > /dev/null
+    fi
+    if request "Do you want to use this identity to login to this machine?"
+    then
+      echo "Adding to ${pwdhome}/.ssh/authorized_keys2"
+      cat "${pwdhome}/.ssh/id_rsa.pub" >> "${pwdhome}/.ssh/authorized_keys2"
+    fi
+  fi
+fi
+
+if [ ! -f "${pwdhome}/.ssh/id_dsa" ]
+then
+  if request "Shall I create an SSH2 DSA identity file for you? (yes/no) "
+  then
+    echo "Generating ${pwdhome}/.ssh/id_dsa"
+    if [ "${with_passphrase}" = "yes" ]
+    then
+      ssh-keygen -t dsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_dsa" > /dev/null
+    else
+      ssh-keygen -t dsa -f "${pwdhome}/.ssh/id_dsa" > /dev/null
+    fi
+    if request "Do you want to use this identity to login to this machine?"
+    then
+      echo "Adding to ${pwdhome}/.ssh/authorized_keys2"
+      cat "${pwdhome}/.ssh/id_dsa.pub" >> "${pwdhome}/.ssh/authorized_keys2"
+    fi
+  fi
+fi
+
+echo
+echo "Configuration finished. Have fun!"
diff --git a/openssh/contrib/gnome-ssh-askpass.c b/openssh/contrib/gnome-ssh-askpass.c
new file mode 100644 (file)
index 0000000..27e5cca
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Compile with:
+ *
+ * cc `gnome-config --cflags gnome gnomeui` \
+ *    gnome-ssh-askpass.c -o gnome-ssh-askpass \
+ *    `gnome-config --libs gnome gnomeui`
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnome.h>
+#include <X11/Xlib.h>
+#include <gdk/gdkx.h>
+
+void
+report_failed_grab (void)
+{
+       GtkWidget *err;
+
+       err = gnome_message_box_new("Could not grab keyboard or mouse.\n"
+               "A malicious client may be eavesdropping on your session.",
+                                   GNOME_MESSAGE_BOX_ERROR, "EXIT", NULL);
+       gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
+       gtk_object_set(GTK_OBJECT(err), "type", GTK_WINDOW_POPUP, NULL);
+
+       gnome_dialog_run_and_close(GNOME_DIALOG(err));
+}
+
+void
+passphrase_dialog(char *message)
+{
+       char *passphrase;
+       char **messages;
+       int result, i;
+       
+       GtkWidget *dialog, *entry, *label;
+
+       dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK,
+           GNOME_STOCK_BUTTON_CANCEL, NULL);
+
+       messages = g_strsplit(message, "\\n", 0);
+       if (messages)
+               for(i = 0; messages[i]; i++) {
+                       label = gtk_label_new(messages[i]);
+                       gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
+                           label, FALSE, FALSE, 0);
+               }
+
+       entry = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE, 
+           FALSE, 0);
+       gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+       gtk_widget_grab_focus(entry);
+
+       /* Center window and prepare for grab */
+       gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL);
+       gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
+       gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+       gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
+       gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE);
+       gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox),
+           GNOME_PAD);
+       gtk_widget_show_all(dialog);
+
+       /* Grab focus */
+       XGrabServer(GDK_DISPLAY());
+       if (gdk_pointer_grab(dialog->window, TRUE, 0, NULL, NULL, 
+           GDK_CURRENT_TIME))
+               goto nograb;
+       if (gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME))
+               goto nograbkb;
+
+       /* Make <enter> close dialog */
+       gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
+
+       /* Run dialog */
+       result = gnome_dialog_run(GNOME_DIALOG(dialog));
+
+       /* Ungrab */
+       XUngrabServer(GDK_DISPLAY());
+       gdk_pointer_ungrab(GDK_CURRENT_TIME);
+       gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+       gdk_flush();
+
+       /* Report passphrase if user selected OK */
+       passphrase = gtk_entry_get_text(GTK_ENTRY(entry));
+       if (result == 0)
+               puts(passphrase);
+               
+       /* Zero passphrase in memory */
+       memset(passphrase, '\0', strlen(passphrase));
+       gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
+                       
+       gnome_dialog_close(GNOME_DIALOG(dialog));
+       return;
+
+       /* At least one grab failed - ungrab what we got, and report
+          the failure to the user.  Note that XGrabServer() cannot
+          fail.  */
+ nograbkb:
+       gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ nograb:
+       XUngrabServer(GDK_DISPLAY());
+       gnome_dialog_close(GNOME_DIALOG(dialog));
+       
+       report_failed_grab();
+}
+
+int
+main(int argc, char **argv)
+{
+       char *message;
+       
+       gnome_init("GNOME ssh-askpass", "0.1", argc, argv);
+
+       if (argc == 2)
+               message = argv[1];
+       else
+               message = "Enter your OpenSSH passphrase:";
+
+       setvbuf(stdout, 0, _IONBF, 0);
+       passphrase_dialog(message);
+       return 0;
+}
diff --git a/openssh/contrib/hpux/README b/openssh/contrib/hpux/README
new file mode 100644 (file)
index 0000000..f8bfa84
--- /dev/null
@@ -0,0 +1,45 @@
+README for OpenSSH HP-UX contrib files
+Kevin Steves <stevesk@pobox.com>
+
+sshd:          configuration file for sshd.rc
+sshd.rc:       SSH startup script
+egd:           configuration file for egd.rc
+egd.rc:                EGD (entropy gathering daemon) startup script
+
+To install:
+
+sshd.rc:
+
+o Verify paths in sshd.rc match your local installation
+  (WHAT_PATH and WHAT_PID)
+o Customize sshd if needed (SSHD_ARGS)
+o Install:
+
+  # cp sshd /etc/rc.config.d
+  # chmod 444 /etc/rc.config.d/sshd
+  # cp sshd.rc /sbin/init.d
+  # chmod 555 /sbin/init.d/sshd.rc
+  # ln -s /sbin/init.d/sshd.rc /sbin/rc1.d/K100sshd
+  # ln -s /sbin/init.d/sshd.rc /sbin/rc2.d/S900sshd
+
+egd.rc:
+
+o Verify egd.pl path in egd.rc matches your local installation
+  (WHAT_PATH)
+o Customize egd if needed (EGD_ARGS and EGD_LOG)
+o Add pseudo account:
+
+  # groupadd egd
+  # useradd -g egd egd
+  # mkdir -p /etc/opt/egd
+  # chown egd:egd /etc/opt/egd
+  # chmod 711 /etc/opt/egd
+
+o Install:
+
+  # cp egd /etc/rc.config.d
+  # chmod 444 /etc/rc.config.d/egd
+  # cp egd.rc /sbin/init.d
+  # chmod 555 /sbin/init.d/egd.rc
+  # ln -s /sbin/init.d/egd.rc /sbin/rc1.d/K600egd
+  # ln -s /sbin/init.d/egd.rc /sbin/rc2.d/S400egd
diff --git a/openssh/contrib/hpux/egd b/openssh/contrib/hpux/egd
new file mode 100644 (file)
index 0000000..21af0bd
--- /dev/null
@@ -0,0 +1,15 @@
+# EGD_START:           Set to 1 to start entropy gathering daemon
+# EGD_ARGS:            Command line arguments to pass to egd
+# EGD_LOG:             EGD stdout and stderr log file (default /etc/opt/egd/egd.log)
+#
+# To configure the egd environment:
+
+# groupadd egd
+# useradd -g egd egd
+# mkdir -p /etc/opt/egd
+# chown egd:egd /etc/opt/egd
+# chmod 711 /etc/opt/egd
+
+EGD_START=1
+EGD_ARGS='/etc/opt/egd/entropy'
+EGD_LOG=
diff --git a/openssh/contrib/hpux/egd.rc b/openssh/contrib/hpux/egd.rc
new file mode 100755 (executable)
index 0000000..919dea7
--- /dev/null
@@ -0,0 +1,98 @@
+#!/sbin/sh
+
+#
+# egd.rc: EGD start-up and shutdown script
+#
+
+# Allowed exit values:
+#       0 = success; causes "OK" to show up in checklist.
+#       1 = failure; causes "FAIL" to show up in checklist.
+#       2 = skip; causes "N/A" to show up in the checklist.
+#           Use this value if execution of this script is overridden
+#           by the use of a control variable, or if this script is not
+#           appropriate to execute for some other reason.
+#       3 = reboot; causes the system to be rebooted after execution.
+
+# Input and output:
+#       stdin is redirected from /dev/null
+#
+#       stdout and stderr are redirected to the /etc/rc.log file
+#       during checklist mode, or to the console in raw mode.
+
+umask 022
+
+PATH=/usr/sbin:/usr/bin:/sbin
+export PATH
+
+WHAT='EGD (entropy gathering daemon)'
+WHAT_PATH=/opt/perl/bin/egd.pl
+WHAT_CONFIG=/etc/rc.config.d/egd
+WHAT_LOG=/etc/opt/egd/egd.log
+
+# NOTE: If your script executes in run state 0 or state 1, then /usr might
+#       not be available.  Do not attempt to access commands or files in
+#       /usr unless your script executes in run state 2 or greater.  Other
+#       file systems typically not mounted until run state 2 include /var
+#       and /opt.
+
+rval=0
+
+# Check the exit value of a command run by this script.  If non-zero, the
+# exit code is echoed to the log file and the return value of this script
+# is set to indicate failure.
+
+set_return() {
+       x=$?
+       if [ $x -ne 0 ]; then
+               echo "EXIT CODE: $x"
+               rval=1  # script FAILed
+       fi
+}
+
+case $1 in
+'start_msg')
+       echo "Starting $WHAT"
+       ;;
+
+'stop_msg')
+       echo "Stopping $WHAT"
+       ;;
+
+'start')
+       if [ -f $WHAT_CONFIG ] ; then
+               . $WHAT_CONFIG
+       else
+               echo "ERROR: $WHAT_CONFIG defaults file MISSING"
+       fi
+       
+
+       if [ "$EGD_START" -eq 1 -a -x $WHAT_PATH ]; then
+               EGD_LOG=${EGD_LOG:-$WHAT_LOG}
+               su egd -c "nohup $WHAT_PATH $EGD_ARGS >$EGD_LOG 2>&1" &&
+                       echo $WHAT started
+               set_return
+       else
+               rval=2
+       fi
+       ;;
+
+'stop')
+       pid=`ps -fuegd | awk '$1 == "egd" { print $2 }'`
+       if [ "X$pid" != "X" ]; then
+               if kill "$pid"; then
+                       echo "$WHAT stopped"
+               else
+                       rval=1
+                       echo "Unable to stop $WHAT"
+               fi
+       fi
+       set_return
+       ;;
+
+*)
+       echo "usage: $0 {start|stop|start_msg|stop_msg}"
+       rval=1
+       ;;
+esac
+
+exit $rval
diff --git a/openssh/contrib/hpux/sshd b/openssh/contrib/hpux/sshd
new file mode 100644 (file)
index 0000000..8eb5e92
--- /dev/null
@@ -0,0 +1,5 @@
+# SSHD_START:          Set to 1 to start SSH daemon
+# SSHD_ARGS:           Command line arguments to pass to sshd
+#
+SSHD_START=1
+SSHD_ARGS=
diff --git a/openssh/contrib/hpux/sshd.rc b/openssh/contrib/hpux/sshd.rc
new file mode 100755 (executable)
index 0000000..f9a1099
--- /dev/null
@@ -0,0 +1,90 @@
+#!/sbin/sh
+
+#
+# sshd.rc: SSH daemon start-up and shutdown script
+#
+
+# Allowed exit values:
+#      0 = success; causes "OK" to show up in checklist.
+#      1 = failure; causes "FAIL" to show up in checklist.
+#      2 = skip; causes "N/A" to show up in the checklist.
+#           Use this value if execution of this script is overridden
+#          by the use of a control variable, or if this script is not
+#          appropriate to execute for some other reason.
+#       3 = reboot; causes the system to be rebooted after execution.
+
+# Input and output:
+#      stdin is redirected from /dev/null
+#
+#      stdout and stderr are redirected to the /etc/rc.log file
+#      during checklist mode, or to the console in raw mode.
+
+PATH=/usr/sbin:/usr/bin:/sbin
+export PATH
+
+WHAT='OpenSSH'
+WHAT_PATH=/opt/openssh/sbin/sshd
+WHAT_PID=/var/run/sshd.pid
+WHAT_CONFIG=/etc/rc.config.d/sshd
+
+# NOTE: If your script executes in run state 0 or state 1, then /usr might
+#      not be available.  Do not attempt to access commands or files in
+#      /usr unless your script executes in run state 2 or greater.  Other
+#      file systems typically not mounted until run state 2 include /var
+#      and /opt.
+
+rval=0
+
+# Check the exit value of a command run by this script.  If non-zero, the
+# exit code is echoed to the log file and the return value of this script
+# is set to indicate failure.
+
+set_return() {
+       x=$?
+       if [ $x -ne 0 ]; then
+               echo "EXIT CODE: $x"
+               rval=1  # script FAILed
+       fi
+}
+
+case $1 in
+'start_msg')
+       echo "Starting $WHAT"
+       ;;
+
+'stop_msg')
+       echo "Stopping $WHAT"
+       ;;
+
+'start')
+       if [ -f $WHAT_CONFIG ] ; then
+               . $WHAT_CONFIG
+       else
+               echo "ERROR: $WHAT_CONFIG defaults file MISSING"
+       fi
+       
+       if [ "$SSHD_START" -eq 1 -a -x "$WHAT_PATH" ]; then
+               $WHAT_PATH $SSHD_ARGS && echo "$WHAT started"
+               set_return
+       else
+               rval=2
+       fi
+       ;;
+
+'stop')
+       if kill `cat $WHAT_PID`; then
+               echo "$WHAT stopped"
+       else
+               rval=1
+               echo "Unable to stop $WHAT"
+       fi
+       set_return
+       ;;
+
+*)
+       echo "usage: $0 {start|stop|start_msg|stop_msg}"
+       rval=1
+       ;;
+esac
+
+exit $rval
diff --git a/openssh/contrib/redhat/openssh.spec b/openssh/contrib/redhat/openssh.spec
new file mode 100644 (file)
index 0000000..8ab6859
--- /dev/null
@@ -0,0 +1,335 @@
+# Version of OpenSSH
+%define oversion 3.0.2p1
+
+# Version of ssh-askpass
+%define aversion 1.2.4.1
+
+# Do we want to disable building of x11-askpass? (1=yes 0=no)
+%define no_x11_askpass 0
+
+# Do we want to disable building of gnome-askpass? (1=yes 0=no)
+%define no_gnome_askpass 0
+
+# Do we want to link against a static libcrypto? (1=yes 0=no)
+%define static_libcrypto 0
+
+# Do we want smartcard support (1=yes 0=no)
+%define scard 0
+
+# Use Redhat 7.0 pam control file
+%define redhat7 0
+
+# Disable IPv6 (avoids DNS hangs on some glibc versions)
+%define noip6 0
+
+# Reserve options to override askpass settings with:
+# rpm -ba|--rebuild --define 'skip_xxx 1'
+%{?skip_x11_askpass:%define no_x11_askpass 1}
+%{?skip_gnome_askpass:%define no_gnome_askpass 1}
+
+# Options for Redhat version:
+# rpm -ba|--rebuild --define "rh7 1"
+%{?rh7:%define redhat7 1}
+
+# Options for static OpenSSL link:
+# rpm -ba|--rebuild --define "static_openssl 1"
+%{?static_openssl:%define static_libcrypto 1}
+
+# Options for Smartcard support: (needs libsectok and openssl-engine)
+# rpm -ba|--rebuild --define "smartcard 1"
+%{?smartcard:%define scard 1}
+
+# Option to disable ipv6
+# rpm -ba|--rebuild --define "noipv6 1"
+%{?noipv6:%define noip6 1}
+
+%define exact_openssl_version   %(rpm -q openssl | cut -d - -f 2)
+
+Summary: The OpenSSH implementation of SSH protocol versions 1 and 2
+Name: openssh
+Version: %{oversion}
+Release: 1
+Packager: Damien Miller <djm@mindrot.org>
+URL: http://www.openssh.com/portable.html
+Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{oversion}.tar.gz
+%if ! %{no_x11_askpass}
+Source1: http://www.pobox.com/~jmknoble/software/x11-ssh-askpass/x11-ssh-askpass-%{aversion}.tar.gz
+%endif
+License: BSD
+Group: Applications/Internet
+BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
+Obsoletes: ssh
+BuildPreReq: perl, openssl-devel, tcp_wrappers
+BuildPreReq: /bin/login, /usr/include/security/pam_appl.h
+BuildPreReq: rpm >= 3.0.5
+%if ! %{no_x11_askpass}
+BuildPreReq: XFree86-devel
+%endif
+%if ! %{no_gnome_askpass}
+BuildPreReq: gnome-libs-devel
+%endif
+%if ! %{static_libcrypto}
+PreReq: openssl >= 0.9.5a
+PreReq: openssl = %{exact_openssl_version}
+Requires: openssl >= 0.9.5a
+%endif
+Requires: rpm >= 3.0.5
+
+%package clients
+Summary: OpenSSH clients.
+Requires: openssh = %{version}-%{release}
+Group: Applications/Internet
+Obsoletes: ssh-clients
+
+%package server
+Summary: The OpenSSH server daemon.
+Group: System Environment/Daemons
+Obsoletes: ssh-server
+PreReq: openssh = %{version}-%{release}, chkconfig >= 0.9
+%if %{redhat7}
+Requires: /etc/pam.d/system-auth
+%endif
+
+%package askpass
+Summary: A passphrase dialog for OpenSSH and X.
+Group: Applications/Internet
+Requires: openssh = %{version}-%{release}
+Obsoletes: ssh-extras
+
+%package askpass-gnome
+Summary: A passphrase dialog for OpenSSH, X, and GNOME.
+Group: Applications/Internet
+Requires: openssh = %{version}-%{release}
+Obsoletes: ssh-extras
+
+%description
+OpenSSH is OpenBSD's SSH (Secure SHell) protocol implementation. SSH
+replaces rlogin and rsh, to provide 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. Public key authentication may be used for "passwordless"
+access to servers.
+
+This package includes the core files necessary for both the OpenSSH
+client and server. To make this package useful, you should also
+install openssh-clients, openssh-server, or both.
+
+%description clients
+OpenSSH is OpenBSD's SSH (Secure SHell) protocol implementation.
+
+This package includes the clients necessary to make encrypted
+connections to SSH protocol servers.  You'll also need to install the
+openssh package on OpenSSH clients.
+
+%description server
+OpenSSH is OpenBSD's SSH (Secure SHell) protocol implementation.
+
+This package contains the secure shell daemon (sshd). The sshd daemon
+allows SSH clients to securely connect to your SSH server. You also
+need to have the openssh package installed.
+
+%description askpass
+OpenSSH is OpenBSD's SSH (Secure SHell) protocol implementation.
+
+This package contains an X11 passphrase dialog for OpenSSH.
+
+%description askpass-gnome
+OpenSSH is OpenBSD's SSH (Secure SHell) protocol implementation.
+
+This package contains an X11 passphrase dialog for OpenSSH and the
+GNOME GUI desktop environment.
+
+%prep
+
+%if ! %{no_x11_askpass}
+%setup -q -a 1
+%else
+%setup -q
+%endif
+
+%build
+
+%define _sysconfdir /etc/ssh
+
+EXTRA_OPTS=""
+
+%if %{scard}
+       EXTRA_OPTS="$EXTRA_OPTS --with-smartcard"
+%endif
+
+%if %{noip6}
+       EXTRA_OPTS="$EXTRA_OPTS --with-ipv4-default "
+%endif
+
+%configure \
+       --libexecdir=%{_libexecdir}/openssh \
+       --datadir=%{_datadir}/openssh \
+       --with-pam \
+       --with-tcp-wrappers \
+       --with-rsh=/usr/bin/rsh \
+       --with-default-path=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin \
+       $EXTRA_OPTS
+
+%if %{static_libcrypto}
+perl -pi -e "s|-lcrypto|/usr/lib/libcrypto.a|g" Makefile
+%endif
+
+make
+
+%if ! %{no_x11_askpass}
+pushd x11-ssh-askpass-%{aversion}
+%configure \
+        --libexecdir=%{_libexecdir}/openssh
+xmkmf -a
+make
+popd
+%endif
+
+%if ! %{no_gnome_askpass}
+pushd contrib
+gcc -O -g `gnome-config --cflags gnome gnomeui` \
+        gnome-ssh-askpass.c -o gnome-ssh-askpass \
+        `gnome-config --libs gnome gnomeui`
+popd
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%{makeinstall} \
+       libexecdir=$RPM_BUILD_ROOT%{_libexecdir}/openssh \
+       datadir=$RPM_BUILD_ROOT%{_datadir}/openssh \
+       DESTDIR=/ # Hack to disable key generation
+
+
+install -d $RPM_BUILD_ROOT/etc/pam.d/
+install -d $RPM_BUILD_ROOT/etc/rc.d/init.d
+install -d $RPM_BUILD_ROOT%{_libexecdir}/openssh
+%if %{redhat7}
+install -m644 contrib/redhat/sshd.pam-7.x $RPM_BUILD_ROOT/etc/pam.d/sshd
+%else
+install -m644 contrib/redhat/sshd.pam $RPM_BUILD_ROOT/etc/pam.d/sshd
+%endif
+install -m755 contrib/redhat/sshd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/sshd
+
+%if ! %{no_x11_askpass}
+install -s x11-ssh-askpass-%{aversion}/x11-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/x11-ssh-askpass
+ln -s /usr/libexec/openssh/x11-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/ssh-askpass
+%endif
+
+%if ! %{no_gnome_askpass}
+install -s contrib/gnome-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/gnome-ssh-askpass
+%endif
+
+perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/*
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post server
+/sbin/chkconfig --add sshd
+if test -r /var/run/sshd.pid ; then
+       /etc/rc.d/init.d/sshd restart >&2
+fi
+
+%preun server
+if [ "$1" = 0 ] ; then
+       /etc/rc.d/init.d/sshd stop >&2
+       /sbin/chkconfig --del sshd
+fi
+
+%files
+%defattr(-,root,root)
+%doc CREDITS ChangeLog INSTALL LICENCE OVERVIEW README* RFC* TODO WARNING*
+%attr(0755,root,root) %{_bindir}/ssh-keygen
+%attr(0755,root,root) %{_bindir}/scp
+%attr(0644,root,root) %{_mandir}/man1/ssh-keygen.1*
+%attr(0644,root,root) %{_mandir}/man1/scp.1*
+%attr(0755,root,root) %dir %{_sysconfdir}
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/moduli
+%attr(0755,root,root) %dir %{_libexecdir}/openssh
+%if %{scard}
+%attr(0755,root,root) %dir %{_datadir}/openssh
+%attr(0644,root,root) %{_datadir}/openssh/Ssh.bin
+%endif
+
+%files clients
+%defattr(-,root,root)
+%attr(4755,root,root) %{_bindir}/ssh
+%attr(0755,root,root) %{_bindir}/ssh-agent
+%attr(0755,root,root) %{_bindir}/ssh-add
+%attr(0755,root,root) %{_bindir}/ssh-keyscan
+%attr(0755,root,root) %{_bindir}/sftp
+%attr(0644,root,root) %{_mandir}/man1/ssh.1*
+%attr(0644,root,root) %{_mandir}/man1/ssh-agent.1*
+%attr(0644,root,root) %{_mandir}/man1/ssh-add.1*
+%attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1*
+%attr(0644,root,root) %{_mandir}/man1/sftp.1*
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh_config
+%attr(-,root,root) %{_bindir}/slogin
+%attr(-,root,root) %{_mandir}/man1/slogin.1*
+
+%files server
+%defattr(-,root,root)
+%attr(0755,root,root) %{_sbindir}/sshd
+%attr(0755,root,root) %{_libexecdir}/openssh/sftp-server
+%attr(0644,root,root) %{_mandir}/man8/sshd.8*
+%attr(0644,root,root) %{_mandir}/man8/sftp-server.8*
+#%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sshd_config
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sshd_config
+%attr(0600,root,root) %config(noreplace) /etc/pam.d/sshd
+%attr(0755,root,root) %config /etc/rc.d/init.d/sshd
+
+%if ! %{no_x11_askpass}
+%files askpass
+%defattr(-,root,root)
+%doc x11-ssh-askpass-%{aversion}/README
+%doc x11-ssh-askpass-%{aversion}/ChangeLog
+%doc x11-ssh-askpass-%{aversion}/SshAskpass*.ad
+%attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass
+%attr(0755,root,root) %{_libexecdir}/openssh/x11-ssh-askpass
+%endif
+
+%if ! %{no_gnome_askpass}
+%files askpass-gnome
+%defattr(-,root,root)
+%attr(0755,root,root) %{_libexecdir}/openssh/gnome-ssh-askpass
+%endif
+
+%changelog
+* Mon Oct 18 2000 Damien Miller <djm@mindrot.org>
+- Merge some of Nalin Dahyabhai <nalin@redhat.com> changes from the 
+  Redhat 7.0 spec file
+* Tue Sep 05 2000 Damien Miller <djm@mindrot.org>
+- Use RPM configure macro
+* Tue Aug 08 2000 Damien Miller <djm@mindrot.org>
+- Some surgery to sshd.init (generate keys at runtime)
+- Cleanup of groups and removal of keygen calls
+* Wed Jul 12 2000 Damien Miller <djm@mindrot.org>
+- Make building of X11-askpass and gnome-askpass optional
+* Mon Jun 12 2000 Damien Miller <djm@mindrot.org>
+- Glob manpages to catch compressed files
+* Wed Mar 15 2000 Damien Miller <djm@ibs.com.au>
+- Updated for new location
+- Updated for new gnome-ssh-askpass build
+* Sun Dec 26 1999 Damien Miller <djm@mindrot.org>
+- Added Jim Knoble's <jmknoble@pobox.com> askpass
+* Mon Nov 15 1999 Damien Miller <djm@mindrot.org>
+- Split subpackages further based on patch from jim knoble <jmknoble@pobox.com>
+* Sat Nov 13 1999 Damien Miller <djm@mindrot.org>
+- Added 'Obsoletes' directives
+* Tue Nov 09 1999 Damien Miller <djm@ibs.com.au>
+- Use make install
+- Subpackages
+* Mon Nov 08 1999 Damien Miller <djm@ibs.com.au>
+- Added links for slogin
+- Fixed perms on manpages
+* Sat Oct 30 1999 Damien Miller <djm@ibs.com.au>
+- Renamed init script
+* Fri Oct 29 1999 Damien Miller <djm@ibs.com.au>
+- Back to old binary names
+* Thu Oct 28 1999 Damien Miller <djm@ibs.com.au>
+- Use autoconf
+- New binary names
+* Wed Oct 27 1999 Damien Miller <djm@ibs.com.au>
+- Initial RPMification, based on Jan "Yenya" Kasprzak's <kas@fi.muni.cz> spec.
+
diff --git a/openssh/contrib/redhat/sshd.init b/openssh/contrib/redhat/sshd.init
new file mode 100755 (executable)
index 0000000..86b040c
--- /dev/null
@@ -0,0 +1,163 @@
+#!/bin/bash
+
+# Init file for OpenSSH server daemon
+#
+# chkconfig: 2345 55 25
+# description: OpenSSH server daemon
+#
+# processname: sshd
+# config: /etc/ssh/ssh_host_key
+# config: /etc/ssh/ssh_host_key.pub
+# config: /etc/ssh/ssh_random_seed
+# config: /etc/ssh/sshd_config
+# pidfile: /var/run/sshd.pid
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+[ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd
+
+RETVAL=0
+
+# Some functions to make the below more readable
+KEYGEN=/usr/bin/ssh-keygen
+RSA1_KEY=/etc/ssh/ssh_host_key
+RSA_KEY=/etc/ssh/ssh_host_rsa_key
+DSA_KEY=/etc/ssh/ssh_host_dsa_key
+PID_FILE=/var/run/sshd.pid
+my_success() {
+  local msg
+  if [ $# -gt 1 ]; then
+    msg="$2"
+  else
+    msg="done"
+  fi
+  case "`type -type success`" in
+    function)
+      success "$1"
+    ;;
+    *)
+      echo -n "${msg}"
+    ;;
+  esac
+}
+my_failure() {
+  local msg
+  if [ $# -gt 1 ]; then
+    msg="$2"
+  else
+    msg="FAILED"
+  fi
+  case "`type -type failure`" in
+    function)
+      failure "$1"
+    ;;
+    *)
+      echo -n "${msg}"
+    ;;
+  esac
+}
+do_rsa1_keygen() {
+       if ! test -f $RSA1_KEY ; then
+               echo -n "Generating SSH1 RSA host key: "
+               if $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then
+                       my_success "RSA1 key generation"
+                       echo
+               else
+                       my_failure "RSA1 key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+do_rsa_keygen() {
+       if ! test -f $RSA_KEY ; then
+               echo -n "Generating SSH2 RSA host key: "
+               if $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then
+                       my_success "RSA key generation"
+                       echo
+               else
+                       my_failure "RSA key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+do_dsa_keygen() {
+       if ! test -f $DSA_KEY ; then
+               echo -n "Generating SSH2 DSA host key: "
+               if $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then
+                       my_success "DSA key generation"
+                       echo
+               else
+                       my_failure "DSA key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+do_restart_sanity_check() {
+       sshd -t
+       RETVAL=$?
+       if [ ! "$RETVAL" = 0 ]; then
+               my_failure "Configuration file or keys"
+               echo
+               exit $RETVAL
+       fi
+}
+
+
+case "$1" in
+       start)
+               # Create keys if necessary
+               do_rsa1_keygen;
+               do_rsa_keygen;
+               do_dsa_keygen;
+               
+               echo -n "Starting sshd: "
+               if [ ! -f $PID_FILE ] ; then
+                       sshd $OPTIONS
+                       RETVAL=$?
+                       if [ "$RETVAL" = "0" ] ; then
+                               my_success "sshd startup" "sshd"
+                               touch /var/lock/subsys/sshd
+                       else
+                               my_failure "sshd startup" ""
+                       fi
+               fi
+               echo
+               ;;
+       stop)
+               echo -n "Shutting down sshd: "
+               if [ -f $PID_FILE ] ; then
+                       killproc sshd
+                       RETVAL=$?
+                       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/sshd
+               fi
+               echo
+               ;;
+       restart)
+               do_restart_sanity_check
+               $0 stop
+               $0 start
+               RETVAL=$?
+               ;;
+       condrestart)
+               if [ -f /var/lock/subsys/sshd ] ; then
+                       do_restart_sanity_check
+                       $0 stop
+                       $0 start
+                       RETVAL=$?
+               fi
+               ;;
+       status)
+               status sshd
+               RETVAL=$?
+               ;;
+       *)
+               echo "Usage: sshd {start|stop|restart|status|condrestart}"
+               exit 1
+               ;;
+esac
+
+exit $RETVAL
diff --git a/openssh/contrib/redhat/sshd.pam b/openssh/contrib/redhat/sshd.pam
new file mode 100644 (file)
index 0000000..26dcb34
--- /dev/null
@@ -0,0 +1,8 @@
+#%PAM-1.0
+auth       required     /lib/security/pam_pwdb.so shadow nodelay
+auth       required     /lib/security/pam_nologin.so
+account    required     /lib/security/pam_pwdb.so
+password   required     /lib/security/pam_cracklib.so
+password   required     /lib/security/pam_pwdb.so shadow nullok use_authtok
+session    required     /lib/security/pam_pwdb.so
+session    required     /lib/security/pam_limits.so
diff --git a/openssh/contrib/redhat/sshd.pam-7.x b/openssh/contrib/redhat/sshd.pam-7.x
new file mode 100644 (file)
index 0000000..d2ab073
--- /dev/null
@@ -0,0 +1,8 @@
+#%PAM-1.0
+auth       required     /lib/security/pam_stack.so service=system-auth
+auth       required     /lib/security/pam_nologin.so
+account    required     /lib/security/pam_stack.so service=system-auth
+password   required     /lib/security/pam_stack.so service=system-auth
+session    required     /lib/security/pam_stack.so service=system-auth
+session    required     /lib/security/pam_limits.so
+session    optional     /lib/security/pam_console.so
diff --git a/openssh/contrib/solaris/README b/openssh/contrib/solaris/README
new file mode 100644 (file)
index 0000000..5585249
--- /dev/null
@@ -0,0 +1,28 @@
+The following is a new package build script for Solaris.   This is being
+introduced into OpenSSH 3.0 and above in hopes of simplifying the build
+process.  
+
+The build process is called a 'dummy install'.. Which means the software does
+a  "make install-nokeys DESTDIR=[fakeroot]".  This way all manpages should
+be handled correctly and key are defered until the first time the sshd
+is started.
+
+Directions:
+
+1. make -F Makefile.in distprep  (Only if you are getting from the CVS tree)
+2. ./configure --with-pam [..any other options you want..]
+3. cd contrib/solaris; ./buildpkg.sh
+
+If all goes well you should have a solaris package ready to be installed.
+
+If you have any problems with this script please post them to 
+openssh-unix-dev@mindrot.org and I will try to assist you as best as I can.
+
+- Ben Lindstrom
+
+TODO:
+- Expand to cover all sysvr4 family of OSes
+- Clean things up a bit more.  
+- Detect if sshd is running and refuse to start.
+- SHOULD check for existing sshd_config nor ssh_config (does not currently).
+  [Post install script?  Ugh.. Nasty]
diff --git a/openssh/contrib/solaris/buildpkg.sh b/openssh/contrib/solaris/buildpkg.sh
new file mode 100755 (executable)
index 0000000..05abb22
--- /dev/null
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+# Fake Root Solaris Build System - Prototype
+#
+# The following code has been provide under Public Domain License.  I really
+# don't care what you use it for.  Just as long as you don't complain to me
+# nor my employer if you break it. - Ben Lindstrom (mouring@eviladmin.org)
+# 
+umask 022
+PKGNAME=OpenSSH
+
+## Extract common info requires for the 'info' part of the package.
+VERSION=`tail -1 ../../version.h | sed -e 's/.*_\([0-9]\)/\1/g' | sed 's/\"$//'`
+ARCH=`uname -p`
+
+## Start by faking root install 
+echo "Faking root install..."
+START=`pwd`
+FAKE_ROOT=$START/package
+mkdir $FAKE_ROOT
+cd ../..
+make install-nokeys DESTDIR=$FAKE_ROOT
+
+## Fill in some details, like prefix and sysconfdir
+ETCDIR=`grep "^sysconfdir=" Makefile | sed 's/sysconfdir=//'`
+PREFIX=`grep "^prefix=" Makefile | cut -d = -f 2`        
+PIDDIR=`grep "^piddir=" Makefile | cut -d = -f 2`        
+cd $FAKE_ROOT
+
+## Setup our run level stuff while we are at it.
+mkdir -p $FAKE_ROOT/etc/init.d
+mkdir -p $FAKE_ROOT/etc/rcS.d
+mkdir -p $FAKE_ROOT/etc/rc0.d
+mkdir -p $FAKE_ROOT/etc/rc1.d
+mkdir -p $FAKE_ROOT/etc/rc2.d
+
+
+## setup our initscript correctly
+sed -e "s#%%configDir%%#$ETCDIR#g"             \
+    -e "s#%%openSSHDir%%#$PREFIX#g"    \
+    -e "s#%%pidDir%%#$PIDDIR#g"        \
+       ../opensshd.in  > $FAKE_ROOT/etc/init.d/opensshd
+chmod 711 $FAKE_ROOT/etc/init.d/opensshd
+
+ln -s ../init.d/opensshd $FAKE_ROOT/etc/rcS.d/K30opensshd
+ln -s ../init.d/opensshd $FAKE_ROOT/etc/rc0.d/K30opensshd
+ln -s ../init.d/opensshd $FAKE_ROOT/etc/rc1.d/K30opensshd
+ln -s ../init.d/opensshd $FAKE_ROOT/etc/rc2.d/S98opensshd
+
+
+## Ok, this is outright wrong, but it will work.  I'm tired of pkgmk
+## whining.
+for i in *; do
+  PROTO_ARGS="$PROTO_ARGS $i=/$i";
+done
+
+## Build info file
+echo "Building pkginfo file..."
+cat > pkginfo << _EOF
+PKG=$PKGNAME
+NAME=OpenSSH Portable for Solaris
+DESC="Secure Shell remote access utility; replaces telnet and rlogin/rsh."
+VENDOR="OpenSSH Portable Team - http://www.openssh.com/portable.html"
+BASEDIR=$FAKE_ROOT
+ARCH=$ARCH
+VERSION=$VERSION
+CATEGORY=Security
+BASEDIR=/
+_EOF
+
+## Next Build our prototype
+echo "Building prototype file..."
+find . | egrep -v "prototype|pkginfo" | sort | pkgproto $PROTO_ARGS | \
+       awk '
+            BEGIN { print "i pkginfo" }        
+           { $5="root"; $6="sys"; }
+           { print; }' > prototype
+
+## Step back a directory and now build the package.
+echo "Building package.."
+cd ..
+pkgmk -d . -f $FAKE_ROOT/prototype -o
+rm -rf $FAKE_ROOT
+echo | pkgtrans -os . $PKGNAME-$ARCH-$VERSION.pkg
+rm -rf $PKGNAME
diff --git a/openssh/contrib/solaris/opensshd.in b/openssh/contrib/solaris/opensshd.in
new file mode 100755 (executable)
index 0000000..212254d
--- /dev/null
@@ -0,0 +1,90 @@
+#!/sbin/sh
+# Donated code that was put under PD license.
+#
+# Stripped PRNGd out of it for the time being.
+
+AWK=/usr/bin/awk
+CAT=/usr/bin/cat
+KILL=/usr/bin/kill
+PS=/usr/bin/ps
+XARGS=/usr/bin/xargs
+
+prefix=%%openSSHDir%%
+etcdir=%%configDir%%
+piddir=%%pidDir%%
+
+SSHD=$prefix/sbin/sshd
+PIDFILE=$piddir/sshd.pid
+SSH_KEYGEN=$prefix/bin/ssh-keygen
+HOST_KEY_RSA1=$etcdir/ssh_host_key
+HOST_KEY_DSA=$etcdir/ssh_host_dsa_key
+HOST_KEY_RSA=$etcdir/ssh_host_rsa_key
+
+killproc() {
+   _procname=$1
+   _signal=$2
+   ${PS} -u root | ${AWK} '/'"$_procname"'$/ {print $1}' | ${XARGS} ${KILL}
+}
+
+
+checkkeys() {
+    if [ ! -f $HOST_KEY_RSA1 ]; then
+        ${SSH_KEYGEN} -t rsa1 -f ${HOST_KEY_RSA1} -N ""
+    fi
+    if [ ! -f $HOST_KEY_DSA ]; then
+        ${SSH_KEYGEN} -t dsa -f ${HOST_KEY_DSA} -N ""
+    fi
+    if [ ! -f $HOST_KEY_RSA ]; then
+        ${SSH_KEYGEN} -t rsa -f ${HOST_KEY_RSA} -N ""
+    fi
+}
+
+stop_service() {
+    if [  -r $PIDFILE  -a  ! -z ${PIDFILE}  ]; then
+        PID=`${CAT} ${PIDFILE}`
+    fi
+    if [  ${PID:=0} -gt 1 -a  ! "X$PID" = "X "  ]; then
+        ${KILL} ${PID}
+    else
+        echo "Unable to read PID file, killing using alternate method"
+        killproc sshd TERM
+    fi
+}
+
+start_service() {
+    # XXX We really should check if the service is already going, but
+    # XXX we will opt out at this time. - Bal
+
+    # Check to see if we have keys that need to be made
+    checkkeys
+
+    # Start SSHD
+    echo "starting $SSHD... \c"         ; $SSHD
+
+    sshd_rc=$?
+    if [ $sshd_rc -ne 0 ]; then
+        echo "$0: Error ${sshd_rc} starting ${SSHD}... bailing."
+        exit $sshd_rc
+    fi
+    echo done.
+}
+
+case $1 in
+
+'start')
+    start_service
+    ;;
+
+'stop')
+    stop_service
+    ;;
+
+'restart')
+    stop_service
+    start_service
+    ;;
+
+*)
+    echo "$0:  usage:  $0 {start|stop|restart}"
+    ;;
+esac
diff --git a/openssh/contrib/ssh-copy-id b/openssh/contrib/ssh-copy-id
new file mode 100644 (file)
index 0000000..2346761
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# Shell script to install your identity.pub on a remote machine
+# Takes the remote machine name as an argument.
+# Obviously, the remote machine must accept password authentication,
+# or one of the other keys in your ssh-agent, for this to work.
+
+ID_FILE="${HOME}/.ssh/identity.pub"
+
+if [ "-i" = "$1" ]; then
+  shift
+  # check if we have 2 parameters left, if so the first is the new ID file
+  if [ -n "$2" ]; then
+    if expr "$1" : ".*\.pub" ; then
+      ID_FILE="$1"
+    else
+      ID_FILE="$1.pub"
+    fi
+    shift         # and this should leave $1 as the target name
+  fi
+else
+  if [ x$SSH_AUTH_SOCK != x ] ; then
+    GET_ID="$GET_ID ssh-add -L"
+  fi
+fi
+
+if [ -z "`eval $GET_ID`" -a -r "${ID_FILE}" ] ; then
+  GET_ID="cat ${ID_FILE}"
+fi
+
+if [ -z "`eval $GET_ID`" ]; then
+  echo "$0: ERROR: No identities found"
+  exit 1
+fi
+
+{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys"
+
+cat <<EOF
+Now try logging into the machine, with "ssh '$1'", and check in:
+
+  .ssh/authorized_keys
+
+to make sure we haven't added extra keys that you weren't expecting.
+
+EOF
diff --git a/openssh/contrib/ssh-copy-id.1 b/openssh/contrib/ssh-copy-id.1
new file mode 100644 (file)
index 0000000..b331fa1
--- /dev/null
@@ -0,0 +1,67 @@
+.ig \"  -*- nroff -*-
+Copyright (c) 1999 Philip Hands Computing <http://www.hands.com/>
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+..
+.TH SSH-COPY-ID 1 "14 November 1999" "OpenSSH"
+.SH NAME
+ssh-copy-id \- install your identity.pub in a remote machine's authorized_keys
+.SH SYNOPSIS
+.B ssh-copy-id [-i [identity_file]]
+.I "[user@]machine"
+.br
+.SH DESCRIPTION
+.BR ssh-copy-id
+is a script that uses ssh to log into a remote machine (presumably
+using a login password, so password authentication should be enabled,
+unless you've done some clever use of multiple identities)
+.PP
+It also changes the permissions of the remote user's home,
+.BR ~/.ssh ,
+and
+.B ~/.ssh/authorized_keys
+to remove group writability (which would otherwise prevent you from logging in, if the remote
+.B sshd
+has
+.B StrictModes
+set in its configuration).
+.PP
+If the
+.B -i
+option is given then the identity file (defaults to
+.BR ~/.ssh/identity.pub )
+is used, regardless of whether there are any keys in your
+.BR ssh-agent .
+Otherwise, if this:
+.PP
+.B "      ssh-add -L"
+.PP
+provides any output, it uses that in preference to the identity file.
+.PP
+If the
+.B -i
+option is used, or the
+.B ssh-add
+produced no output, then it uses the contents of the identity
+file.  Once it has one or more fingerprints (by whatever means) it
+uses ssh to append them to
+.B ~/.ssh/authorized_keys
+on the remote machine (creating the file, and directory, if necessary)
+
+.SH "SEE ALSO"
+.BR ssh (1),
+.BR ssh-agent (1),
+.BR sshd (8)
diff --git a/openssh/contrib/sshd.pam.freebsd b/openssh/contrib/sshd.pam.freebsd
new file mode 100644 (file)
index 0000000..c0bc364
--- /dev/null
@@ -0,0 +1,5 @@
+sshd    auth      required  pam_unix.so    try_first_pass
+sshd    account   required  pam_unix.so
+sshd    password  required  pam_permit.so
+sshd    session   required  pam_permit.so
+
diff --git a/openssh/contrib/sshd.pam.generic b/openssh/contrib/sshd.pam.generic
new file mode 100644 (file)
index 0000000..cf5af30
--- /dev/null
@@ -0,0 +1,8 @@
+#%PAM-1.0
+auth       required     /lib/security/pam_unix.so shadow nodelay
+auth       required     /lib/security/pam_nologin.so
+account    required     /lib/security/pam_unix.so
+password   required     /lib/security/pam_cracklib.so
+password   required     /lib/security/pam_unix.so shadow nullok use_authtok
+session    required     /lib/security/pam_unix.so
+session    required     /lib/security/pam_limits.so
diff --git a/openssh/contrib/suse/openssh.spec b/openssh/contrib/suse/openssh.spec
new file mode 100644 (file)
index 0000000..b3bc0c0
--- /dev/null
@@ -0,0 +1,199 @@
+Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
+Name: openssh
+Version: 3.0.2p1
+URL: http://www.openssh.com/
+Release: 1
+Source0: openssh-%{version}.tar.gz
+Copyright: BSD
+Group: Applications/Internet
+BuildRoot: /tmp/openssh-%{version}-buildroot
+PreReq: openssl
+Obsoletes: ssh
+#
+# (Build[ing] Prereq[uisites] only work for RPM 2.95 and newer.)
+# building prerequisites -- stuff for
+#   OpenSSL (openssl-devel),
+#   TCP Wrappers (nkitb),
+#   and Gnome (glibdev, gtkdev, and gnlibsd)
+#
+BuildPrereq: openssl
+BuildPrereq: nkitb
+BuildPrereq: glibdev
+BuildPrereq: gtkdev
+BuildPrereq: gnlibsd
+
+%description
+Ssh (Secure Shell) a program for logging into a remote machine and for
+executing commands in a remote machine.  It is intended to replace
+rlogin and rsh, and provide 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.
+
+OpenSSH is OpenBSD's rework of the last free version of SSH, bringing it
+up to date in terms of security and features, as well as removing all 
+patented algorithms to seperate libraries (OpenSSL).
+
+This package includes all files necessary for both the OpenSSH
+client and server. Additionally, this package contains the GNOME
+passphrase dialog.
+
+%changelog
+* Mon Jun 12 2000 Damien Miller <djm@mindrot.org>
+- Glob manpages to catch compressed files
+* Wed Mar 15 2000 Damien Miller <djm@ibs.com.au>
+- Updated for new location
+- Updated for new gnome-ssh-askpass build
+* Sun Dec 26 1999 Chris Saia <csaia@wtower.com>
+- Made symlink to gnome-ssh-askpass called ssh-askpass
+* Wed Nov 24 1999 Chris Saia <csaia@wtower.com>
+- Removed patches that included /etc/pam.d/sshd, /sbin/init.d/rc.sshd, and
+  /var/adm/fillup-templates/rc.config.sshd, since Damien merged these into
+  his released tarfile
+- Changed permissions on ssh_config in the install procedure to 644 from 600
+  even though it was correct in the %files section and thus right in the RPMs
+- Postinstall script for the server now only prints "Generating SSH host
+  key..." if we need to actually do this, in order to eliminate a confusing
+  message if an SSH host key is already in place
+- Marked all manual pages as %doc(umentation)
+* Mon Nov 22 1999 Chris Saia <csaia@wtower.com>
+- Added flag to configure daemon with TCP Wrappers support
+- Added building prerequisites (works in RPM 3.0 and newer)
+* Thu Nov 18 1999 Chris Saia <csaia@wtower.com>
+- Made this package correct for SuSE.
+- Changed instances of pam_pwdb.so to pam_unix.so, since it works more properly
+  with SuSE, and lib_pwdb.so isn't installed by default.
+* Mon Nov 15 1999 Damien Miller <djm@mindrot.org>
+- Split subpackages further based on patch from jim knoble <jmknoble@pobox.com>
+* Sat Nov 13 1999 Damien Miller <djm@mindrot.org>
+- Added 'Obsoletes' directives
+* Tue Nov 09 1999 Damien Miller <djm@ibs.com.au>
+- Use make install
+- Subpackages
+* Mon Nov 08 1999 Damien Miller <djm@ibs.com.au>
+- Added links for slogin
+- Fixed perms on manpages
+* Sat Oct 30 1999 Damien Miller <djm@ibs.com.au>
+- Renamed init script
+* Fri Oct 29 1999 Damien Miller <djm@ibs.com.au>
+- Back to old binary names
+* Thu Oct 28 1999 Damien Miller <djm@ibs.com.au>
+- Use autoconf
+- New binary names
+* Wed Oct 27 1999 Damien Miller <djm@ibs.com.au>
+- Initial RPMification, based on Jan "Yenya" Kasprzak's <kas@fi.muni.cz> spec.
+
+%prep
+
+%setup -q
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" \
+./configure    --prefix=/usr \
+               --sysconfdir=/etc/ssh \
+               --datadir=/usr/share/openssh \
+               --with-pam \
+               --with-gnome-askpass \
+               --with-tcp-wrappers \
+               --with-ipv4-default \
+               --libexecdir=/usr/lib/ssh
+make
+
+cd contrib
+gcc -O -g `gnome-config --cflags gnome gnomeui` \
+        gnome-ssh-askpass.c -o gnome-ssh-askpass \
+        `gnome-config --libs gnome gnomeui`
+cd ..
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT/
+install -d $RPM_BUILD_ROOT/etc/ssh/
+install -d $RPM_BUILD_ROOT/etc/pam.d/
+install -d $RPM_BUILD_ROOT/sbin/init.d/
+install -d $RPM_BUILD_ROOT/var/adm/fillup-templates
+install -d $RPM_BUILD_ROOT/usr/lib/ssh
+install -m644 contrib/sshd.pam.generic $RPM_BUILD_ROOT/etc/pam.d/sshd
+install -m744 contrib/suse/rc.sshd $RPM_BUILD_ROOT/sbin/init.d/sshd
+ln -s ../../sbin/init.d/sshd $RPM_BUILD_ROOT/usr/sbin/rcsshd
+install -s contrib/gnome-ssh-askpass $RPM_BUILD_ROOT/usr/lib/ssh/gnome-ssh-askpass
+ln -s gnome-ssh-askpass $RPM_BUILD_ROOT/usr/lib/ssh/ssh-askpass
+install -m744 contrib/suse/rc.config.sshd \
+   $RPM_BUILD_ROOT/var/adm/fillup-templates
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+if [ "$1" = 1 ]; then
+  echo "Creating SSH stop/start scripts in the rc directories..."
+  ln -s ../sshd /sbin/init.d/rc2.d/K20sshd
+  ln -s ../sshd /sbin/init.d/rc2.d/S20sshd
+  ln -s ../sshd /sbin/init.d/rc3.d/K20sshd
+  ln -s ../sshd /sbin/init.d/rc3.d/S20sshd
+fi
+echo "Updating /etc/rc.config..."
+if [ -x /bin/fillup ] ; then
+  /bin/fillup -q -d = etc/rc.config var/adm/fillup-templates/rc.config.sshd
+else
+  echo "ERROR: fillup not found.  This should NOT happen in SuSE Linux."
+  echo "Update /etc/rc.config by hand from the following template file:"
+  echo "  /var/adm/fillup-templates/rc.config.sshd"
+fi
+if [ ! -f /etc/ssh/ssh_host_key -o ! -s /etc/ssh/ssh_host_key ]; then
+        echo "Generating SSH host key..."
+       /usr/bin/ssh-keygen -b 1024 -f /etc/ssh/ssh_host_key -N '' >&2
+fi
+if [ ! -f /etc/ssh/ssh_host_dsa_key -o ! -s /etc/ssh/ssh_host_dsa_key ]; then
+        echo "Generating SSH DSA host key..."
+       /usr/bin/ssh-keygen -d -f /etc/ssh/ssh_host_dsa_key -N '' >&2
+fi
+if test -r /var/run/sshd.pid
+then
+        echo "Restarting the running SSH daemon..."
+       /usr/sbin/rcsshd restart >&2
+fi
+
+%preun
+if [ "$1" = 0 ]
+then
+        echo "Stopping the SSH daemon..."
+       /usr/sbin/rcsshd stop >&2
+       echo "Removing SSH stop/start scripts from the rc directories..."
+        rm /sbin/init.d/rc2.d/K20sshd
+        rm /sbin/init.d/rc2.d/S20sshd
+        rm /sbin/init.d/rc3.d/K20sshd
+        rm /sbin/init.d/rc3.d/S20sshd
+fi
+
+%files
+%defattr(-,root,root)
+%doc ChangeLog OVERVIEW README* 
+%doc RFC.nroff TODO CREDITS LICENSE
+%attr(0755,root,root) %dir /etc/ssh
+%attr(0644,root,root) %config /etc/ssh/ssh_config
+%attr(0600,root,root) %config /etc/ssh/sshd_config
+%attr(0600,root,root) %config /etc/ssh/moduli
+%attr(0644,root,root) %config /etc/pam.d/sshd
+%attr(0755,root,root) %config /sbin/init.d/sshd
+%attr(0755,root,root) /usr/bin/ssh-keygen
+%attr(0755,root,root) /usr/bin/scp
+%attr(4755,root,root) /usr/bin/ssh
+%attr(-,root,root) /usr/bin/slogin
+%attr(0755,root,root) /usr/bin/ssh-agent
+%attr(0755,root,root) /usr/bin/ssh-add
+%attr(0755,root,root) /usr/bin/ssh-keyscan
+%attr(0755,root,root) /usr/bin/sftp
+%attr(0755,root,root) /usr/sbin/sshd
+%attr(-,root,root) /usr/sbin/rcsshd
+%attr(0755,root,root) %dir /usr/lib/ssh
+%attr(0755,root,root) /usr/lib/ssh/ssh-askpass
+%attr(0755,root,root) /usr/lib/ssh/gnome-ssh-askpass
+%attr(0644,root,root) %doc /usr/man/man1/scp.1*
+%attr(0644,root,root) %doc /usr/man/man1/ssh.1*
+%attr(-,root,root) %doc /usr/man/man1/slogin.1*
+%attr(0644,root,root) %doc /usr/man/man1/ssh-agent.1*
+%attr(0644,root,root) %doc /usr/man/man1/ssh-add.1*
+%attr(0644,root,root) %doc /usr/man/man1/ssh-keygen.1*
+%attr(0644,root,root) %doc /usr/man/man8/sshd.8*
+%attr(0644,root,root) /var/adm/fillup-templates/rc.config.sshd
+
diff --git a/openssh/contrib/suse/rc.config.sshd b/openssh/contrib/suse/rc.config.sshd
new file mode 100644 (file)
index 0000000..baaa7a5
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Start the Secure Shell (SSH) Daemon?
+#
+START_SSHD="yes"
+
diff --git a/openssh/contrib/suse/rc.sshd b/openssh/contrib/suse/rc.sshd
new file mode 100644 (file)
index 0000000..f7d431e
--- /dev/null
@@ -0,0 +1,80 @@
+#! /bin/sh
+# Copyright (c) 1995-1998 SuSE GmbH Nuernberg, Germany.
+#
+# Author: Chris Saia <csaia@wtower.com>
+#
+# /sbin/init.d/sshd
+#
+#   and symbolic its link
+#
+# /sbin/rcsshd
+#
+
+. /etc/rc.config
+
+# Determine the base and follow a runlevel link name.
+base=${0##*/}
+link=${base#*[SK][0-9][0-9]}
+
+# Force execution if not called by a runlevel directory.
+test $link = $base && START_SSHD=yes
+test "$START_SSHD" = yes || exit 0
+
+# The echo return value for success (defined in /etc/rc.config).
+return=$rc_done
+case "$1" in
+    start)
+       echo -n "Starting service sshd"
+       ## Start daemon with startproc(8). If this fails
+       ## the echo return value is set appropriate.
+
+       startproc /usr/sbin/sshd || return=$rc_failed
+
+       echo -e "$return"
+       ;;
+    stop)
+       echo -n "Stopping service sshd"
+       ## Stop daemon with killproc(8) and if this fails
+       ## set echo the echo return value.
+
+       killproc -TERM /usr/sbin/sshd || return=$rc_failed
+
+       echo -e "$return"
+       ;;
+    restart)
+       ## If first returns OK call the second, if first or
+       ## second command fails, set echo return value.
+       $0 stop  &&  $0 start  ||  return=$rc_failed
+       ;;
+    reload)
+       ## Choose ONE of the following two cases:
+
+       ## First possibility: A few services accepts a signal
+       ## to reread the (changed) configuration.
+
+       echo -n "Reload service sshd"
+       killproc -HUP /usr/sbin/sshd || return=$rc_failed
+       echo -e "$return"
+       ;;
+    status)
+       echo -n "Checking for service sshd"
+       ## Check status with checkproc(8), if process is running
+       ## checkproc will return with exit status 0.
+
+       checkproc /usr/sbin/sshd && echo OK || echo No process
+       ;;
+    probe)
+       ## Optional: Probe for the necessity of a reload,
+       ## give out the argument which is required for a reload.
+
+       test /etc/ssh/sshd_config -nt /var/run/sshd.pid && echo reload
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|status|restart|reload[|probe]}"
+       exit 1
+       ;;
+esac
+
+# Inform the caller not only verbosely and set an exit status.
+test "$return" = "$rc_done" || exit 1
+exit 0
diff --git a/openssh/crc32.c b/openssh/crc32.c
new file mode 100644 (file)
index 0000000..4774c8b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be u_(bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ */
+
+
+#include "includes.h"
+RCSID("$OpenBSD: crc32.c,v 1.8 2000/12/19 23:17:56 markus Exp $");
+
+#include "crc32.h"
+
+static u_int crc32_tab[] = {
+       0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+       0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+       0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+       0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+       0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+       0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+       0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+       0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+       0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+       0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+       0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+       0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+       0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+       0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+       0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+       0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+       0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+       0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+       0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+       0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+       0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+       0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+       0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+       0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+       0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+       0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+       0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+       0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+       0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+       0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+       0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+       0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+       0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+       0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+       0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+       0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+       0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+       0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+       0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+       0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+       0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+       0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+       0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+       0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+       0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+       0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+       0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+       0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+       0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+       0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+       0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+       0x2d02ef8dL
+};
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+u_int
+ssh_crc32(const u_char *s, u_int len)
+{
+       u_int i;
+       u_int crc32val;
+
+       crc32val = 0;
+       for (i = 0;  i < len;  i ++) {
+               crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+       }
+       return crc32val;
+}
diff --git a/openssh/crc32.h b/openssh/crc32.h
new file mode 100644 (file)
index 0000000..bdabc1b
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1992 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for computing 32-bit CRC.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: crc32.h,v 1.12 2001/06/26 17:27:23 markus Exp $"); */
+
+#ifndef CRC32_H
+#define CRC32_H
+
+u_int   ssh_crc32(const u_char *, u_int);
+
+#endif                         /* CRC32_H */
diff --git a/openssh/deattack.c b/openssh/deattack.c
new file mode 100644 (file)
index 0000000..1a89be4
--- /dev/null
@@ -0,0 +1,155 @@
+/*     $OpenBSD: deattack.c,v 1.14 2001/06/23 15:12:18 itojun Exp $    */
+
+/*
+ * Cryptographic attack detector for ssh - source code
+ *
+ * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
+ *
+ * All rights reserved. Redistribution and use in source and binary
+ * forms, with or without modification, are permitted provided that
+ * this copyright notice is retained.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
+ * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
+ * SOFTWARE.
+ *
+ * Ariel Futoransky <futo@core-sdi.com>
+ * <http://www.core-sdi.com>
+ */
+
+#include "includes.h"
+#include "deattack.h"
+#include "log.h"
+#include "crc32.h"
+#include "getput.h"
+#include "xmalloc.h"
+
+/* SSH Constants */
+#define SSH_MAXBLOCKS  (32 * 1024)
+#define SSH_BLOCKSIZE  (8)
+
+/* Hashing constants */
+#define HASH_MINSIZE   (8 * 1024)
+#define HASH_ENTRYSIZE (2)
+#define HASH_FACTOR(x) ((x)*3/2)
+#define HASH_UNUSEDCHAR        (0xff)
+#define HASH_UNUSED    (0xffff)
+#define HASH_IV        (0xfffe)
+
+#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
+
+
+/* Hash function (Input keys are cipher results) */
+#define HASH(x)                GET_32BIT(x)
+
+#define CMP(a, b)      (memcmp(a, b, SSH_BLOCKSIZE))
+
+static void
+crc_update(u_int32_t *a, u_int32_t b)
+{
+       b ^= *a;
+       *a = ssh_crc32((u_char *) &b, sizeof(b));
+}
+
+/* detect if a block is used in a particular pattern */
+static int
+check_crc(u_char *S, u_char *buf, u_int32_t len,
+         u_char *IV)
+{
+       u_int32_t crc;
+       u_char *c;
+
+       crc = 0;
+       if (IV && !CMP(S, IV)) {
+               crc_update(&crc, 1);
+               crc_update(&crc, 0);
+       }
+       for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
+               if (!CMP(S, c)) {
+                       crc_update(&crc, 1);
+                       crc_update(&crc, 0);
+               } else {
+                       crc_update(&crc, 0);
+                       crc_update(&crc, 0);
+               }
+       }
+       return (crc == 0);
+}
+
+
+/* Detect a crc32 compensation attack on a packet */
+int
+detect_attack(u_char *buf, u_int32_t len, u_char *IV)
+{
+       static u_int16_t *h = (u_int16_t *) NULL;
+       static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
+       register u_int32_t i, j;
+       u_int32_t l;
+       register u_char *c;
+       u_char *d;
+
+       if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
+           len % SSH_BLOCKSIZE != 0) {
+               fatal("detect_attack: bad length %d", len);
+       }
+       for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
+               ;
+
+       if (h == NULL) {
+               debug("Installing crc compensation attack detector.");
+               n = l;
+               h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
+       } else {
+               if (l > n) {
+                       n = l;
+                       h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
+               }
+       }
+
+       if (len <= HASH_MINBLOCKS) {
+               for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
+                       if (IV && (!CMP(c, IV))) {
+                               if ((check_crc(c, buf, len, IV)))
+                                       return (DEATTACK_DETECTED);
+                               else
+                                       break;
+                       }
+                       for (d = buf; d < c; d += SSH_BLOCKSIZE) {
+                               if (!CMP(c, d)) {
+                                       if ((check_crc(c, buf, len, IV)))
+                                               return (DEATTACK_DETECTED);
+                                       else
+                                               break;
+                               }
+                       }
+               }
+               return (DEATTACK_OK);
+       }
+       memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
+
+       if (IV)
+               h[HASH(IV) & (n - 1)] = HASH_IV;
+
+       for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
+               for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
+                    i = (i + 1) & (n - 1)) {
+                       if (h[i] == HASH_IV) {
+                               if (!CMP(c, IV)) {
+                                       if (check_crc(c, buf, len, IV))
+                                               return (DEATTACK_DETECTED);
+                                       else
+                                               break;
+                               }
+                       } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
+                               if (check_crc(c, buf, len, IV))
+                                       return (DEATTACK_DETECTED);
+                               else
+                                       break;
+                       }
+               }
+               h[i] = j;
+       }
+       return (DEATTACK_OK);
+}
diff --git a/openssh/deattack.h b/openssh/deattack.h
new file mode 100644 (file)
index 0000000..ddccdea
--- /dev/null
@@ -0,0 +1,30 @@
+/*     $OpenBSD: deattack.h,v 1.7 2001/06/26 17:27:23 markus Exp $     */
+
+/*
+ * Cryptographic attack detector for ssh - Header file
+ *
+ * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
+ *
+ * All rights reserved. Redistribution and use in source and binary
+ * forms, with or without modification, are permitted provided that
+ * this copyright notice is retained.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
+ * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
+ * SOFTWARE.
+ *
+ * Ariel Futoransky <futo@core-sdi.com>
+ * <http://www.core-sdi.com>
+ */
+
+#ifndef _DEATTACK_H
+#define _DEATTACK_H
+
+/* Return codes */
+#define DEATTACK_OK            0
+#define DEATTACK_DETECTED      1
+
+int     detect_attack(u_char *, u_int32_t, u_char[8]);
+#endif
diff --git a/openssh/defines.h b/openssh/defines.h
new file mode 100644 (file)
index 0000000..3c2287e
--- /dev/null
@@ -0,0 +1,558 @@
+#ifndef _DEFINES_H
+#define _DEFINES_H
+
+/* $Id$ */
+
+/* Necessary headers */
+
+#include <sys/types.h> /* For [u]intxx_t */
+#include <sys/socket.h> /* For SHUT_XXXX */
+#include <sys/param.h> /* For MAXPATHLEN and roundup() */
+#include <netinet/in_systm.h> /* For typedefs */
+#include <netinet/in.h> /* For IPv6 macros */
+#include <netinet/ip.h> /* For IPTOS macros */
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h> /* For sockaddr_un */
+#endif
+#ifdef HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h> /* For u_intXX_t */
+#endif
+#ifdef HAVE_PATHS_H
+# include <paths.h> /* For _PATH_XXX */
+#endif
+#ifdef HAVE_LIMITS_H
+# include <limits.h> /* For PATH_MAX */
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h> /* For timersub */
+#endif
+#ifdef HAVE_MAILLOCK_H
+# include <maillock.h> /* For _PATH_MAILDIR */
+#endif
+#ifdef HAVE_SYS_CDEFS_H
+# include <sys/cdefs.h> /* For __P() */
+#endif
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h> /* For MIN, MAX, etc */
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h> /* For S_* constants and macros */
+#endif
+#ifdef HAVE_NEXT
+#  include <libc.h>
+#endif
+
+#include <unistd.h> /* For STDIN_FILENO, etc */
+#include <termios.h> /* Struct winsize */
+#include <fcntl.h> /* For O_NONBLOCK */
+#include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */
+
+/* *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_LOGIN_H
+# include <login.h>
+#endif
+
+
+/* Constants */
+
+#ifndef SHUT_RDWR
+enum
+{
+  SHUT_RD = 0,         /* No more receptions.  */
+  SHUT_WR,                     /* No more transmissions.  */
+  SHUT_RDWR                    /* No more receptions or transmissions.  */
+};
+# define SHUT_RD   SHUT_RD
+# define SHUT_WR   SHUT_WR
+# define SHUT_RDWR SHUT_RDWR
+#endif
+
+#ifndef IPTOS_LOWDELAY
+# define IPTOS_LOWDELAY          0x10
+# define IPTOS_THROUGHPUT        0x08
+# define IPTOS_RELIABILITY       0x04
+# define IPTOS_LOWCOST           0x02
+# define IPTOS_MINCOST           IPTOS_LOWCOST
+#endif /* IPTOS_LOWDELAY */
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+#  define MAXPATHLEN PATH_MAX
+# else /* PATH_MAX */
+#  define MAXPATHLEN 64 /* Should be safe */
+# endif /* PATH_MAX */
+#endif /* MAXPATHLEN */
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO    0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO   1
+#endif
+#ifndef STDERR_FILENO
+# define STDERR_FILENO   2
+#endif
+
+#ifndef NGROUPS_MAX    /* Disable groupaccess if NGROUP_MAX is not set */
+#ifdef NGROUPS
+#define NGROUPS_MAX NGROUPS
+#else
+#define NGROUPS_MAX 0
+#endif
+#endif
+
+#ifndef O_NONBLOCK     /* Non Blocking Open */
+# define O_NONBLOCK      00004
+#endif
+
+#ifndef S_ISDIR
+# define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR))
+#endif /* S_ISDIR */
+
+#ifndef S_ISREG 
+# define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
+#endif /* S_ISREG */
+
+#ifndef S_ISLNK
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif /* S_ISLNK */
+
+#ifndef S_IXUSR
+# define S_IXUSR                       0000100 /* execute/search permission, */
+# define S_IXGRP                       0000010 /* execute/search permission, */
+# define S_IXOTH                       0000001 /* execute/search permission, */
+# define _S_IWUSR                      0000200 /* write permission, */
+# define S_IWUSR                       _S_IWUSR        /* write permission, owner */
+# define S_IWGRP                       0000020 /* write permission, group */
+# define S_IWOTH                       0000002 /* write permission, other */
+# define S_IRUSR                       0000400 /* read permission, owner */
+# define S_IRGRP                       0000040 /* read permission, group */
+# define S_IROTH                       0000004 /* read permission, other */
+# define S_IRWXU                       0000700 /* read, write, execute */
+# define S_IRWXG                       0000070 /* read, write, execute */
+# define S_IRWXO                       0000007 /* read, write, execute */
+#endif /* S_IXUSR */
+
+/* *-*-nto-qnx doesn't define this constant in the system headers */
+#ifdef MISSING_NFDBITS
+# define       NFDBITS (8 * sizeof(unsigned long))
+#endif
+
+/* Types */
+
+/* If sys/types.h does not supply intXX_t, supply them ourselves */
+/* (or die trying) */
+
+
+#ifndef HAVE_U_INT
+typedef unsigned int u_int;
+#endif
+
+#ifndef HAVE_INTXX_T
+# if (SIZEOF_CHAR == 1)
+typedef char int8_t;
+# else
+#  error "8 bit int type not found."
+# endif
+# if (SIZEOF_SHORT_INT == 2)
+typedef short int int16_t;
+# else
+#  ifdef _CRAY
+typedef long  int16_t;
+#  else
+#   error "16 bit int type not found."
+#  endif /* _CRAY */
+# endif
+# if (SIZEOF_INT == 4)
+typedef int int32_t;
+# else
+#  ifdef _CRAY
+typedef long  int32_t;
+#  else
+#   error "32 bit int type not found."
+#  endif /* _CRAY */
+# endif
+#endif
+
+/* If sys/types.h does not supply u_intXX_t, supply them ourselves */
+#ifndef HAVE_U_INTXX_T
+# ifdef HAVE_UINTXX_T
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+# define HAVE_U_INTXX_T 1
+# else
+#  if (SIZEOF_CHAR == 1)
+typedef unsigned char u_int8_t;
+#  else
+#   error "8 bit int type not found."
+#  endif
+#  if (SIZEOF_SHORT_INT == 2)
+typedef unsigned short int u_int16_t;
+#  else
+#   ifdef _CRAY
+typedef unsigned long  u_int16_t;
+#   else
+#    error "16 bit int type not found."
+#   endif
+#  endif
+#  if (SIZEOF_INT == 4)
+typedef unsigned int u_int32_t;
+#  else
+#   ifdef _CRAY
+typedef unsigned long  u_int32_t;
+#   else
+#    error "32 bit int type not found."
+#   endif
+#  endif
+# endif
+#define __BIT_TYPES_DEFINED__
+#endif
+
+/* 64-bit types */
+#ifndef HAVE_INT64_T
+# if (SIZEOF_LONG_INT == 8)
+typedef long int int64_t;
+#   define HAVE_INT64_T 1
+# else
+#  if (SIZEOF_LONG_LONG_INT == 8)
+typedef long long int int64_t;
+#   define HAVE_INT64_T 1
+#  endif
+# endif
+#endif
+#ifndef HAVE_U_INT64_T
+# if (SIZEOF_LONG_INT == 8)
+typedef unsigned long int u_int64_t;
+#   define HAVE_U_INT64_T 1
+# else
+#  if (SIZEOF_LONG_LONG_INT == 8)
+typedef unsigned long long int u_int64_t;
+#   define HAVE_U_INT64_T 1
+#  endif
+# endif
+#endif
+#if !defined(HAVE_LONG_LONG_INT) && (SIZEOF_LONG_LONG_INT == 8)
+# define HAVE_LONG_LONG_INT 1
+#endif
+
+#ifndef HAVE_U_CHAR
+typedef unsigned char u_char;
+# define HAVE_U_CHAR
+#endif /* HAVE_U_CHAR */
+
+#ifndef HAVE_SIZE_T
+typedef unsigned int size_t;
+# define HAVE_SIZE_T
+#endif /* HAVE_SIZE_T */
+
+#ifndef HAVE_SSIZE_T
+typedef int ssize_t;
+# define HAVE_SSIZE_T
+#endif /* HAVE_SSIZE_T */
+
+#ifndef HAVE_CLOCK_T
+typedef long clock_t;
+# define HAVE_CLOCK_T
+#endif /* HAVE_CLOCK_T */
+
+#ifndef HAVE_SA_FAMILY_T
+typedef int sa_family_t;
+# define HAVE_SA_FAMILY_T
+#endif /* HAVE_SA_FAMILY_T */
+
+#ifndef HAVE_PID_T
+typedef int pid_t;
+# define HAVE_PID_T
+#endif /* HAVE_PID_T */
+
+#ifndef HAVE_MODE_T
+typedef int mode_t;
+# define HAVE_MODE_T
+#endif /* HAVE_MODE_T */
+
+#if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS)
+# define ss_family __ss_family
+#endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */
+
+#ifndef HAVE_SYS_UN_H
+struct sockaddr_un {
+       short   sun_family;             /* AF_UNIX */
+       char    sun_path[108];          /* path name (gag) */
+};
+#endif /* HAVE_SYS_UN_H */
+
+#if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE)
+#define _STRUCT_WINSIZE
+struct winsize {
+      unsigned short ws_row;          /* rows, in characters */
+      unsigned short ws_col;          /* columns, in character */
+      unsigned short ws_xpixel;       /* horizontal size, pixels */
+      unsigned short ws_ypixel;       /* vertical size, pixels */
+};
+#endif
+
+/* *-*-nto-qnx does not define this type in the system headers */
+#ifdef MISSING_FD_MASK
+ typedef unsigned long int     fd_mask;
+#endif
+
+/* Paths */
+
+#ifndef _PATH_BSHELL
+# define _PATH_BSHELL "/bin/sh"
+#endif
+#ifndef _PATH_CSHELL
+# define _PATH_CSHELL "/bin/csh"
+#endif
+#ifndef _PATH_SHELLS
+# define _PATH_SHELLS "/etc/shells"
+#endif
+
+#ifdef USER_PATH
+# ifdef _PATH_STDPATH
+#  undef _PATH_STDPATH
+# endif
+# define _PATH_STDPATH USER_PATH
+#endif
+
+#ifndef _PATH_STDPATH
+# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
+#endif
+
+#ifndef _PATH_DEVNULL
+# define _PATH_DEVNULL "/dev/null"
+#endif
+
+#ifndef MAIL_DIRECTORY
+# define MAIL_DIRECTORY "/var/spool/mail"
+#endif
+
+#ifndef MAILDIR
+# define MAILDIR MAIL_DIRECTORY
+#endif
+
+#if !defined(_PATH_MAILDIR) && defined(MAILDIR)
+# define _PATH_MAILDIR MAILDIR
+#endif /* !defined(_PATH_MAILDIR) && defined(MAILDIR) */
+
+#ifndef _PATH_RSH
+# ifdef RSH_PATH
+#  define _PATH_RSH RSH_PATH
+# else /* RSH_PATH */
+#  define _PATH_RSH "/usr/bin/rsh"
+# endif /* RSH_PATH */
+#endif /* _PATH_RSH */
+
+#ifndef _PATH_NOLOGIN
+# define _PATH_NOLOGIN "/etc/nologin"
+#endif
+
+/* Define this to be the path of the xauth program. */
+#ifdef XAUTH_PATH
+#define _PATH_XAUTH XAUTH_PATH
+#endif /* XAUTH_PATH */
+
+#ifndef _PATH_TTY
+# define _PATH_TTY "/dev/tty"
+#endif
+
+/* Macros */
+
+#if defined(HAVE_LOGIN_GETCAPBOOL) && defined(HAVE_LOGIN_CAP_H)
+# define HAVE_LOGIN_CAP
+#endif
+
+#ifndef MAX
+# define MAX(a,b) (((a)>(b))?(a):(b))
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef roundup
+# define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
+#endif
+
+#ifndef timersub
+#define timersub(a, b, result)                                 \
+   do {                                                                \
+      (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;            \
+      (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;         \
+      if ((result)->tv_usec < 0) {                             \
+        --(result)->tv_sec;                                    \
+        (result)->tv_usec += 1000000;                          \
+      }                                                                \
+   } while (0)
+#endif
+
+#ifndef __P
+# define __P(x) x
+#endif
+
+#if !defined(IN6_IS_ADDR_V4MAPPED)
+# define IN6_IS_ADDR_V4MAPPED(a) \
+       ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \
+        (((u_int32_t *) (a))[2] == htonl (0xffff)))
+#endif /* !defined(IN6_IS_ADDR_V4MAPPED) */
+
+#if !defined(__GNUC__) || (__GNUC__ < 2)
+# define __attribute__(x)
+#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
+
+/* *-*-nto-qnx doesn't define this macro in the system headers */
+#ifdef MISSING_HOWMANY
+# define howmany(x,y)  (((x)+((y)-1))/(y))
+#endif
+
+/* Function replacement / compatibility hacks */
+
+/* In older versions of libpam, pam_strerror takes a single argument */
+#ifdef HAVE_OLD_PAM
+# define PAM_STRERROR(a,b) pam_strerror((b))
+#else
+# define PAM_STRERROR(a,b) pam_strerror((a),(b))
+#endif
+
+#ifdef PAM_SUN_CODEBASE
+# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
+#else
+# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
+#endif
+
+#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO)
+# undef HAVE_GETADDRINFO
+#endif
+#if defined(BROKEN_GETADDRINFO) && defined(HAVE_FREEADDRINFO)
+# undef HAVE_FREEADDRINFO
+#endif
+#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GAI_STRERROR)
+# undef HAVE_GAI_STRERROR
+#endif
+
+#if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY)
+# define memmove(s1, s2, n) bcopy((s2), (s1), (n))
+#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */
+
+#if !defined(HAVE_ATEXIT) && defined(HAVE_ON_EXIT)
+# define atexit(a, NULL) on_exit(a, NULL)
+#else
+# if defined(HAVE_XATEXIT)
+#  define atexit(a) xatexit(a)
+# endif /* defined(HAVE_XATEXIT) */
+#endif /* !defined(HAVE_ATEXIT) && defined(HAVE_ON_EXIT) */
+
+#if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX)
+#  define USE_VHANGUP
+#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */
+
+#ifndef GETPGRP_VOID
+# define getpgrp() getpgrp(0)
+#endif
+
+/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */
+#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f)
+# define OPENSSL_free(x) Free(x)
+#endif
+
+/*
+ * Define this to use pipes instead of socketpairs for communicating with the
+ * client program.  Socketpairs do not seem to work on all systems.
+ *
+ * configure.ac sets this for a few OS's which are known to have problems
+ * but you may need to set it yourself
+ */
+/* #define USE_PIPES 1 */
+
+/**
+ ** login recorder definitions
+ **/
+
+/* preprocess */
+
+#ifdef HAVE_UTMP_H
+#  ifdef HAVE_TIME_IN_UTMP
+#    include <time.h>
+#  endif
+#  include <utmp.h>
+#endif
+#ifdef HAVE_UTMPX_H
+#  ifdef HAVE_TV_IN_UTMPX
+#    include <sys/time.h>
+#  endif
+#  include <utmpx.h>
+#endif
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+
+/* FIXME: put default paths back in */
+#ifndef UTMP_FILE
+#  ifdef _PATH_UTMP
+#    define UTMP_FILE _PATH_UTMP
+#  else
+#    ifdef CONF_UTMP_FILE
+#      define UTMP_FILE CONF_UTMP_FILE
+#    endif
+#  endif
+#endif
+#ifndef WTMP_FILE
+#  ifdef _PATH_WTMP
+#    define WTMP_FILE _PATH_WTMP
+#  else
+#    ifdef CONF_WTMP_FILE
+#      define WTMP_FILE CONF_WTMP_FILE
+#    endif
+#  endif
+#endif
+/* pick up the user's location for lastlog if given */
+#ifndef LASTLOG_FILE
+#  ifdef _PATH_LASTLOG
+#    define LASTLOG_FILE _PATH_LASTLOG
+#  else
+#    ifdef CONF_LASTLOG_FILE
+#      define LASTLOG_FILE CONF_LASTLOG_FILE
+#    endif
+#  endif
+#endif
+
+
+/* The login() library function in libutil is first choice */
+#if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN)
+#  define USE_LOGIN
+
+#else
+/* Simply select your favourite login types. */
+/* Can't do if-else because some systems use several... <sigh> */
+#  if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
+#    define USE_UTMPX
+#  endif
+#  if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
+#    define USE_UTMP
+#  endif
+#  if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
+#    define USE_WTMPX
+#  endif
+#  if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
+#    define USE_WTMP
+#  endif
+
+#endif
+
+/* I hope that the presence of LASTLOG_FILE is enough to detect this */
+#if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG)
+#  define USE_LASTLOG
+#endif
+
+/* which type of time to use? (api.c) */
+#ifdef HAVE_SYS_TIME_H
+#  define USE_TIMEVAL
+#endif
+
+/** end of login recorder definitions */
+
+#endif /* _DEFINES_H */
diff --git a/openssh/dh.c b/openssh/dh.c
new file mode 100644 (file)
index 0000000..fa2508a
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2000 Niels Provos.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: dh.c,v 1.17 2001/06/23 15:12:18 itojun Exp $");
+
+#include "xmalloc.h"
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+
+#include "buffer.h"
+#include "cipher.h"
+#include "kex.h"
+#include "dh.h"
+#include "pathnames.h"
+#include "log.h"
+#include "misc.h"
+
+static int
+parse_prime(int linenum, char *line, struct dhgroup *dhg)
+{
+       char *cp, *arg;
+       char *strsize, *gen, *prime;
+
+       cp = line;
+       arg = strdelim(&cp);
+       /* Ignore leading whitespace */
+       if (*arg == '\0')
+               arg = strdelim(&cp);
+       if (!*arg || *arg == '#')
+               return 0;
+
+       /* time */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       arg = strsep(&cp, " "); /* type */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       arg = strsep(&cp, " "); /* tests */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       arg = strsep(&cp, " "); /* tries */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       strsize = strsep(&cp, " "); /* size */
+       if (cp == NULL || *strsize == '\0' ||
+           (dhg->size = atoi(strsize)) == 0)
+               goto fail;
+       /* The whole group is one bit larger */
+       dhg->size++;
+       gen = strsep(&cp, " "); /* gen */
+       if (cp == NULL || *gen == '\0')
+               goto fail;
+       prime = strsep(&cp, " "); /* prime */
+       if (cp != NULL || *prime == '\0')
+               goto fail;
+
+       dhg->g = BN_new();
+       dhg->p = BN_new();
+       if (BN_hex2bn(&dhg->g, gen) == 0)
+               goto failclean;
+
+       if (BN_hex2bn(&dhg->p, prime) == 0)
+               goto failclean;
+
+       if (BN_num_bits(dhg->p) != dhg->size)
+               goto failclean;
+
+       return (1);
+
+ failclean:
+       BN_free(dhg->g);
+       BN_free(dhg->p);
+ fail:
+       error("Bad prime description in line %d", linenum);
+       return (0);
+}
+
+DH *
+choose_dh(int min, int wantbits, int max)
+{
+       FILE *f;
+       char line[2048];
+       int best, bestcount, which;
+       int linenum;
+       struct dhgroup dhg;
+
+       if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
+           (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
+               log("WARNING: %s does not exist, using old modulus", _PATH_DH_MODULI);
+               return (dh_new_group1());
+       }
+
+       linenum = 0;
+       best = bestcount = 0;
+       while (fgets(line, sizeof(line), f)) {
+               linenum++;
+               if (!parse_prime(linenum, line, &dhg))
+                       continue;
+               BN_free(dhg.g);
+               BN_free(dhg.p);
+
+               if (dhg.size > max || dhg.size < min)
+                       continue;
+
+               if ((dhg.size > wantbits && dhg.size < best) ||
+                   (dhg.size > best && best < wantbits)) {
+                       best = dhg.size;
+                       bestcount = 0;
+               }
+               if (dhg.size == best)
+                       bestcount++;
+       }
+       rewind(f);
+
+       if (bestcount == 0) {
+               fclose(f);
+               log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
+               return (NULL);
+       }
+
+       linenum = 0;
+       which = arc4random() % bestcount;
+       while (fgets(line, sizeof(line), f)) {
+               if (!parse_prime(linenum, line, &dhg))
+                       continue;
+               if ((dhg.size > max || dhg.size < min) ||
+                   dhg.size != best ||
+                   linenum++ != which) {
+                       BN_free(dhg.g);
+                       BN_free(dhg.p);
+                       continue;
+               }
+               break;
+       }
+       fclose(f);
+       if (linenum != which+1)
+               fatal("WARNING: line %d disappeared in %s, giving up",
+                   which, _PATH_DH_PRIMES);
+
+       return (dh_new_group(dhg.g, dhg.p));
+}
+
+/* diffie-hellman-group1-sha1 */
+
+int
+dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
+{
+       int i;
+       int n = BN_num_bits(dh_pub);
+       int bits_set = 0;
+
+       if (dh_pub->neg) {
+               log("invalid public DH value: negativ");
+               return 0;
+       }
+       for (i = 0; i <= n; i++)
+               if (BN_is_bit_set(dh_pub, i))
+                       bits_set++;
+       debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
+
+       /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
+       if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
+               return 1;
+       log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
+       return 0;
+}
+
+void
+dh_gen_key(DH *dh, int need)
+{
+       int i, bits_set = 0, tries = 0;
+
+       if (dh->p == NULL)
+               fatal("dh_gen_key: dh->p == NULL");
+       if (2*need >= BN_num_bits(dh->p))
+               fatal("dh_gen_key: group too small: %d (2*need %d)",
+                   BN_num_bits(dh->p), 2*need);
+       do {
+               if (dh->priv_key != NULL)
+                       BN_free(dh->priv_key);
+               dh->priv_key = BN_new();
+               if (dh->priv_key == NULL)
+                       fatal("dh_gen_key: BN_new failed");
+               /* generate a 2*need bits random private exponent */
+               if (!BN_rand(dh->priv_key, 2*need, 0, 0))
+                       fatal("dh_gen_key: BN_rand failed");
+               if (DH_generate_key(dh) == 0)
+                       fatal("DH_generate_key");
+               for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
+                       if (BN_is_bit_set(dh->priv_key, i))
+                               bits_set++;
+               debug("dh_gen_key: priv key bits set: %d/%d",
+                   bits_set, BN_num_bits(dh->priv_key));
+               if (tries++ > 10)
+                       fatal("dh_gen_key: too many bad keys: giving up");
+       } while (!dh_pub_is_valid(dh, dh->pub_key));
+}
+
+DH *
+dh_new_group_asc(const char *gen, const char *modulus)
+{
+       DH *dh;
+
+       dh = DH_new();
+       if (dh == NULL)
+               fatal("DH_new");
+
+       if (BN_hex2bn(&dh->p, modulus) == 0)
+               fatal("BN_hex2bn p");
+       if (BN_hex2bn(&dh->g, gen) == 0)
+               fatal("BN_hex2bn g");
+
+       return (dh);
+}
+
+/*
+ * This just returns the group, we still need to generate the exchange
+ * value.
+ */
+
+DH *
+dh_new_group(BIGNUM *gen, BIGNUM *modulus)
+{
+       DH *dh;
+
+       dh = DH_new();
+       if (dh == NULL)
+               fatal("DH_new");
+       dh->p = modulus;
+       dh->g = gen;
+
+       return (dh);
+}
+
+DH *
+dh_new_group1(void)
+{
+       static char *gen = "2", *group1 =
+           "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
+           "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
+           "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
+           "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
+           "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
+           "FFFFFFFF" "FFFFFFFF";
+
+       return (dh_new_group_asc(gen, group1));
+}
+
+/*
+ * Estimates the group order for a Diffie-Hellman group that has an
+ * attack complexity approximately the same as O(2**bits).  Estimate
+ * with:  O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
+ */
+
+int
+dh_estimate(int bits)
+{
+
+       if (bits < 64)
+               return (512);   /* O(2**63) */
+       if (bits < 128)
+               return (1024);  /* O(2**86) */
+       if (bits < 192)
+               return (2048);  /* O(2**116) */
+       return (4096);          /* O(2**156) */
+}
diff --git a/openssh/dh.h b/openssh/dh.h
new file mode 100644 (file)
index 0000000..a0c97b2
--- /dev/null
@@ -0,0 +1,48 @@
+/*     $OpenBSD: dh.h,v 1.7 2001/06/26 17:27:23 markus Exp $   */
+
+/*
+ * Copyright (c) 2000 Niels Provos.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef DH_H
+#define DH_H
+
+struct dhgroup {
+       int size;
+       BIGNUM *g;
+       BIGNUM *p;
+};
+
+DH     *choose_dh(int, int, int);
+DH     *dh_new_group_asc(const char *, const char *);
+DH     *dh_new_group(BIGNUM *, BIGNUM *);
+DH     *dh_new_group1(void);
+
+void    dh_gen_key(DH *, int);
+int     dh_pub_is_valid(DH *, BIGNUM *);
+
+int     dh_estimate(int);
+
+#define DH_GRP_MIN     1024
+#define DH_GRP_MAX     8192
+
+#endif
diff --git a/openssh/dispatch.c b/openssh/dispatch.c
new file mode 100644 (file)
index 0000000..64873d5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: dispatch.c,v 1.11 2001/06/10 11:29:20 markus Exp $");
+
+#include "ssh1.h"
+#include "ssh2.h"
+#include "log.h"
+#include "dispatch.h"
+#include "packet.h"
+#include "compat.h"
+
+#define DISPATCH_MIN   0
+#define DISPATCH_MAX   255
+
+dispatch_fn *dispatch[DISPATCH_MAX];
+
+void
+dispatch_protocol_error(int type, int plen, void *ctxt)
+{
+       fatal("dispatch_protocol_error: type %d plen %d", type, plen);
+}
+void
+dispatch_init(dispatch_fn *dflt)
+{
+       int i;
+       for (i = 0; i < DISPATCH_MAX; i++)
+               dispatch[i] = dflt;
+}
+void
+dispatch_set(int type, dispatch_fn *fn)
+{
+       dispatch[type] = fn;
+}
+void
+dispatch_run(int mode, int *done, void *ctxt)
+{
+       for (;;) {
+               int plen;
+               int type;
+
+               if (mode == DISPATCH_BLOCK) {
+                       type = packet_read(&plen);
+               } else {
+                       type = packet_read_poll(&plen);
+                       if (type == SSH_MSG_NONE)
+                               return;
+               }
+               if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
+                       (*dispatch[type])(type, plen, ctxt);
+               else
+                       packet_disconnect("protocol error: rcvd type %d", type);
+               if (done != NULL && *done)
+                       return;
+       }
+}
diff --git a/openssh/dispatch.h b/openssh/dispatch.h
new file mode 100644 (file)
index 0000000..7b94032
--- /dev/null
@@ -0,0 +1,36 @@
+/*     $OpenBSD: dispatch.h,v 1.6 2001/06/26 17:27:23 markus Exp $     */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+enum {
+       DISPATCH_BLOCK,
+       DISPATCH_NONBLOCK
+};
+
+typedef void dispatch_fn(int, int, void *);
+
+void    dispatch_init(dispatch_fn *);
+void    dispatch_set(int, dispatch_fn *);
+void    dispatch_run(int, int *, void *);
+void    dispatch_protocol_error(int, int, void *);
diff --git a/openssh/entropy.c b/openssh/entropy.c
new file mode 100644 (file)
index 0000000..9588f79
--- /dev/null
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <openssl/crypto.h>
+
+/* SunOS 4.4.4 needs this */
+#ifdef HAVE_FLOATINGPOINT_H
+# include <floatingpoint.h>
+#endif /* HAVE_FLOATINGPOINT_H */
+
+#include "ssh.h"
+#include "misc.h"
+#include "xmalloc.h"
+#include "atomicio.h"
+#include "pathnames.h"
+#include "log.h"
+
+RCSID("$Id$");
+
+#ifndef offsetof
+# define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
+/* Number of times to pass through command list gathering entropy */
+#define NUM_ENTROPY_RUNS       1
+
+/* Scale entropy estimates back by this amount on subsequent runs */
+#define SCALE_PER_RUN          10.0
+
+/* Minimum number of commands to be considered valid */
+#define MIN_ENTROPY_SOURCES 16
+
+#define WHITESPACE " \t\n"
+
+#ifndef RUSAGE_SELF
+# define RUSAGE_SELF 0
+#endif
+#ifndef RUSAGE_CHILDREN
+# define RUSAGE_CHILDREN 0
+#endif
+
+#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS)
+# define SAVED_IDS_WORK_WITH_SETEUID
+#endif
+
+static void
+check_openssl_version(void) 
+{
+       if (SSLeay() != OPENSSL_VERSION_NUMBER)
+               fatal("OpenSSL version mismatch. Built against %lx, you "
+                   "have %lx", OPENSSL_VERSION_NUMBER, SSLeay());
+}
+
+#if defined(PRNGD_SOCKET) || defined(PRNGD_PORT)
+# define USE_PRNGD
+#endif
+
+#if defined(USE_PRNGD) || defined(RANDOM_POOL)
+
+#ifdef USE_PRNGD
+/* Collect entropy from PRNGD/EGD */
+int
+get_random_bytes(unsigned char *buf, int len)
+{
+       int fd;
+       char msg[2];
+#ifdef PRNGD_PORT
+       struct sockaddr_in addr;
+#else
+       struct sockaddr_un addr;
+#endif
+       int addr_len, rval, errors;
+       mysig_t old_sigpipe;
+
+       memset(&addr, '\0', sizeof(addr));
+
+#ifdef PRNGD_PORT
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       addr.sin_port = htons(PRNGD_PORT);
+       addr_len = sizeof(struct sockaddr_in);
+#else /* use IP socket PRNGD_SOCKET instead */
+       /* Sanity checks */
+       if (sizeof(PRNGD_SOCKET) > sizeof(addr.sun_path))
+               fatal("Random pool path is too long");
+       if (len > 255)
+               fatal("Too many bytes to read from PRNGD");
+
+       addr.sun_family = AF_UNIX;
+       strlcpy(addr.sun_path, PRNGD_SOCKET, sizeof(addr.sun_path));
+       addr_len = offsetof(struct sockaddr_un, sun_path) +
+           sizeof(PRNGD_SOCKET);
+#endif
+
+       old_sigpipe = mysignal(SIGPIPE, SIG_IGN);
+
+       errors = rval = 0;
+reopen:
+#ifdef PRNGD_PORT
+       fd = socket(addr.sin_family, SOCK_STREAM, 0);
+       if (fd == -1) {
+               error("Couldn't create AF_INET socket: %s", strerror(errno));
+               goto done;
+       }
+#else
+       fd = socket(addr.sun_family, SOCK_STREAM, 0);
+       if (fd == -1) {
+               error("Couldn't create AF_UNIX socket: %s", strerror(errno));
+               goto done;
+       }
+#endif
+
+       if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) {
+#ifdef PRNGD_PORT
+               error("Couldn't connect to PRNGD port %d: %s",
+                   PRNGD_PORT, strerror(errno));
+#else
+               error("Couldn't connect to PRNGD socket \"%s\": %s",
+                   addr.sun_path, strerror(errno));
+#endif
+               goto done;
+       }
+
+       /* Send blocking read request to PRNGD */
+       msg[0] = 0x02;
+       msg[1] = len;
+
+       if (atomicio(write, fd, msg, sizeof(msg)) != sizeof(msg)) {
+               if (errno == EPIPE && errors < 10) {
+                       close(fd);
+                       errors++;
+                       goto reopen;
+               }
+               error("Couldn't write to PRNGD socket: %s",
+                   strerror(errno));
+               goto done;
+       }
+
+       if (atomicio(read, fd, buf, len) != len) {
+               if (errno == EPIPE && errors < 10) {
+                       close(fd);
+                       errors++;
+                       goto reopen;
+               }
+               error("Couldn't read from PRNGD socket: %s",
+                   strerror(errno));
+               goto done;
+       }
+
+       rval = 1;
+done:
+       mysignal(SIGPIPE, old_sigpipe);
+       if (fd != -1)
+               close(fd);
+       return(rval);
+}
+#else /* !USE_PRNGD */
+#ifdef RANDOM_POOL
+/* Collect entropy from /dev/urandom or pipe */
+static int
+get_random_bytes(unsigned char *buf, int len)
+{
+       int random_pool;
+
+       random_pool = open(RANDOM_POOL, O_RDONLY);
+       if (random_pool == -1) {
+               error("Couldn't open random pool \"%s\": %s",
+                       RANDOM_POOL, strerror(errno));
+               return(0);
+       }
+
+       if (atomicio(read, random_pool, buf, len) != len) {
+               error("Couldn't read from random pool \"%s\": %s",
+                       RANDOM_POOL, strerror(errno));
+               close(random_pool);
+               return(0);
+       }
+
+       close(random_pool);
+
+       return(1);
+}
+#endif /* RANDOM_POOL */
+#endif /* USE_PRNGD */
+
+/*
+ * Seed OpenSSL's random number pool from Kernel random number generator
+ * or PRNGD/EGD
+ */
+void
+seed_rng(void)
+{
+       unsigned char buf[32];
+
+       debug("Seeding random number generator");
+
+       if (!get_random_bytes(buf, sizeof(buf))) {
+               if (!RAND_status())
+                       fatal("Entropy collection failed and entropy exhausted");
+       } else {
+               RAND_add(buf, sizeof(buf), sizeof(buf));
+       }
+
+       memset(buf, '\0', sizeof(buf));
+}
+
+void
+init_rng(void) 
+{
+       check_openssl_version();
+}
+
+#else /* defined(USE_PRNGD) || defined(RANDOM_POOL) */
+
+/*
+ * FIXME: proper entropy estimations. All current values are guesses
+ * FIXME: (ATL) do estimates at compile time?
+ * FIXME: More entropy sources
+ */
+
+/* slow command timeouts (all in milliseconds) */
+/* static int entropy_timeout_default = ENTROPY_TIMEOUT_MSEC; */
+static int entropy_timeout_current = ENTROPY_TIMEOUT_MSEC;
+
+static int prng_seed_saved = 0;
+static int prng_initialised = 0;
+uid_t original_uid;
+
+typedef struct
+{
+       /* Proportion of data that is entropy */
+       double rate;
+       /* Counter goes positive if this command times out */
+       unsigned int badness;
+       /* Increases by factor of two each timeout */
+       unsigned int sticky_badness;
+       /* Path to executable */
+       char *path;
+       /* argv to pass to executable */
+       char *args[5];
+       /* full command string (debug) */
+       char *cmdstring;
+} entropy_source_t;
+
+double stir_from_system(void);
+double stir_from_programs(void);
+double stir_gettimeofday(double entropy_estimate);
+double stir_clock(double entropy_estimate);
+double stir_rusage(int who, double entropy_estimate);
+double hash_output_from_command(entropy_source_t *src, char *hash);
+
+/* this is initialised from a file, by prng_read_commands() */
+entropy_source_t *entropy_sources = NULL;
+
+double
+stir_from_system(void)
+{
+       double total_entropy_estimate;
+       long int i;
+
+       total_entropy_estimate = 0;
+
+       i = getpid();
+       RAND_add(&i, sizeof(i), 0.5);
+       total_entropy_estimate += 0.1;
+
+       i = getppid();
+       RAND_add(&i, sizeof(i), 0.5);
+       total_entropy_estimate += 0.1;
+
+       i = getuid();
+       RAND_add(&i, sizeof(i), 0.0);
+       i = getgid();
+       RAND_add(&i, sizeof(i), 0.0);
+
+       total_entropy_estimate += stir_gettimeofday(1.0);
+       total_entropy_estimate += stir_clock(0.5);
+       total_entropy_estimate += stir_rusage(RUSAGE_SELF, 2.0);
+
+       return(total_entropy_estimate);
+}
+
+double
+stir_from_programs(void)
+{
+       int i;
+       int c;
+       double entropy_estimate;
+       double total_entropy_estimate;
+       char hash[SHA_DIGEST_LENGTH];
+
+       total_entropy_estimate = 0;
+       for(i = 0; i < NUM_ENTROPY_RUNS; i++) {
+               c = 0;
+               while (entropy_sources[c].path != NULL) {
+
+                       if (!entropy_sources[c].badness) {
+                               /* Hash output from command */
+                               entropy_estimate = hash_output_from_command(&entropy_sources[c], hash);
+
+                               /* Scale back entropy estimate according to command's rate */
+                               entropy_estimate *= entropy_sources[c].rate;
+
+                               /* Upper bound of entropy estimate is SHA_DIGEST_LENGTH */
+                               if (entropy_estimate > SHA_DIGEST_LENGTH)
+                                       entropy_estimate = SHA_DIGEST_LENGTH;
+
+                               /* Scale back estimates for subsequent passes through list */
+                               entropy_estimate /= SCALE_PER_RUN * (i + 1.0);
+
+                               /* Stir it in */
+                               RAND_add(hash, sizeof(hash), entropy_estimate);
+
+                               debug3("Got %0.2f bytes of entropy from '%s'", entropy_estimate,
+                                       entropy_sources[c].cmdstring);
+
+                               total_entropy_estimate += entropy_estimate;
+
+                       /* Execution times should be a little unpredictable */
+                               total_entropy_estimate += stir_gettimeofday(0.05);
+                               total_entropy_estimate += stir_clock(0.05);
+                               total_entropy_estimate += stir_rusage(RUSAGE_SELF, 0.1);
+                               total_entropy_estimate += stir_rusage(RUSAGE_CHILDREN, 0.1);
+                       } else {
+                               debug2("Command '%s' disabled (badness %d)",
+                                       entropy_sources[c].cmdstring, entropy_sources[c].badness);
+
+                               if (entropy_sources[c].badness > 0)
+                                       entropy_sources[c].badness--;
+                       }
+
+                       c++;
+               }
+       }
+
+       return(total_entropy_estimate);
+}
+
+double
+stir_gettimeofday(double entropy_estimate)
+{
+       struct timeval tv;
+
+       if (gettimeofday(&tv, NULL) == -1)
+               fatal("Couldn't gettimeofday: %s", strerror(errno));
+
+       RAND_add(&tv, sizeof(tv), entropy_estimate);
+
+       return(entropy_estimate);
+}
+
+double
+stir_clock(double entropy_estimate)
+{
+#ifdef HAVE_CLOCK
+       clock_t c;
+
+       c = clock();
+       RAND_add(&c, sizeof(c), entropy_estimate);
+
+       return(entropy_estimate);
+#else /* _HAVE_CLOCK */
+       return(0);
+#endif /* _HAVE_CLOCK */
+}
+
+double
+stir_rusage(int who, double entropy_estimate)
+{
+#ifdef HAVE_GETRUSAGE
+       struct rusage ru;
+
+       if (getrusage(who, &ru) == -1)
+               return(0);
+
+       RAND_add(&ru, sizeof(ru), entropy_estimate);
+
+       return(entropy_estimate);
+#else /* _HAVE_GETRUSAGE */
+       return(0);
+#endif /* _HAVE_GETRUSAGE */
+}
+
+
+static int
+_get_timeval_msec_difference(struct timeval *t1, struct timeval *t2) {
+       int secdiff, usecdiff;
+
+       secdiff = t2->tv_sec - t1->tv_sec;
+       usecdiff = (secdiff*1000000) + (t2->tv_usec - t1->tv_usec);
+       return (int)(usecdiff / 1000);
+}
+
+double
+hash_output_from_command(entropy_source_t *src, char *hash)
+{
+       static int devnull = -1;
+       int p[2];
+       fd_set rdset;
+       int cmd_eof = 0, error_abort = 0;
+       struct timeval tv_start, tv_current;
+       int msec_elapsed = 0;
+       pid_t pid;
+       int status;
+       char buf[16384];
+       int bytes_read;
+       int total_bytes_read;
+       SHA_CTX sha;
+
+       debug3("Reading output from \'%s\'", src->cmdstring);
+
+       if (devnull == -1) {
+               devnull = open("/dev/null", O_RDWR);
+               if (devnull == -1)
+                       fatal("Couldn't open /dev/null: %s", strerror(errno));
+       }
+
+       if (pipe(p) == -1)
+               fatal("Couldn't open pipe: %s", strerror(errno));
+
+       (void)gettimeofday(&tv_start, NULL); /* record start time */
+
+       switch (pid = fork()) {
+               case -1: /* Error */
+                       close(p[0]);
+                       close(p[1]);
+                       fatal("Couldn't fork: %s", strerror(errno));
+                       /* NOTREACHED */
+               case 0: /* Child */
+                       dup2(devnull, STDIN_FILENO);
+                       dup2(p[1], STDOUT_FILENO);
+                       dup2(p[1], STDERR_FILENO);
+                       close(p[0]);
+                       close(p[1]);
+                       close(devnull);
+
+                       setuid(original_uid);
+                       execv(src->path, (char**)(src->args));
+                       debug("(child) Couldn't exec '%s': %s", src->cmdstring,
+                             strerror(errno));
+                       _exit(-1);
+               default: /* Parent */
+                       break;
+       }
+
+       RAND_add(&pid, sizeof(&pid), 0.0);
+
+       close(p[1]);
+
+       /* Hash output from child */
+       SHA1_Init(&sha);
+       total_bytes_read = 0;
+
+       while (!error_abort && !cmd_eof) {
+               int ret;
+               struct timeval tv;
+               int msec_remaining;
+
+               (void) gettimeofday(&tv_current, 0);
+               msec_elapsed = _get_timeval_msec_difference(&tv_start, &tv_current);
+               if (msec_elapsed >= entropy_timeout_current) {
+                       error_abort=1;
+                       continue;
+               }
+               msec_remaining = entropy_timeout_current - msec_elapsed;
+
+               FD_ZERO(&rdset);
+               FD_SET(p[0], &rdset);
+               tv.tv_sec =  msec_remaining / 1000;
+               tv.tv_usec = (msec_remaining % 1000) * 1000;
+
+               ret = select(p[0]+1, &rdset, NULL, NULL, &tv);
+
+               RAND_add(&tv, sizeof(tv), 0.0);
+
+               switch (ret) {
+               case 0:
+                       /* timer expired */
+                       error_abort = 1;
+                       break;
+               case 1:
+                       /* command input */
+                       do {
+                               bytes_read = read(p[0], buf, sizeof(buf));
+                       } while (bytes_read == -1 && errno == EINTR);
+                       RAND_add(&bytes_read, sizeof(&bytes_read), 0.0);
+                       if (bytes_read == -1) {
+                               error_abort = 1;
+                               break;
+                       } else if (bytes_read) {
+                               SHA1_Update(&sha, buf, bytes_read);
+                               total_bytes_read += bytes_read;
+                       } else {
+                               cmd_eof = 1;
+                       }
+                       break;
+               case -1:
+               default:
+                       /* error */
+                       debug("Command '%s': select() failed: %s", src->cmdstring,
+                             strerror(errno));
+                       error_abort = 1;
+                       break;
+               }
+       }
+
+       SHA1_Final(hash, &sha);
+
+       close(p[0]);
+
+       debug3("Time elapsed: %d msec", msec_elapsed);
+
+       if (waitpid(pid, &status, 0) == -1) {
+              error("Couldn't wait for child '%s' completion: %s", src->cmdstring,
+                    strerror(errno));
+               return(0.0);
+       }
+
+       RAND_add(&status, sizeof(&status), 0.0);
+
+       if (error_abort) {
+               /* closing p[0] on timeout causes the entropy command to
+                * SIGPIPE. Take whatever output we got, and mark this command
+                * as slow */
+               debug2("Command '%s' timed out", src->cmdstring);
+               src->sticky_badness *= 2;
+               src->badness = src->sticky_badness;
+               return(total_bytes_read);
+       }
+
+       if (WIFEXITED(status)) {
+               if (WEXITSTATUS(status)==0) {
+                       return(total_bytes_read);
+               } else {
+                       debug2("Command '%s' exit status was %d", src->cmdstring,
+                               WEXITSTATUS(status));
+                       src->badness = src->sticky_badness = 128;
+                       return (0.0);
+               }
+       } else if (WIFSIGNALED(status)) {
+               debug2("Command '%s' returned on uncaught signal %d !", src->cmdstring,
+                       status);
+               src->badness = src->sticky_badness = 128;
+               return(0.0);
+       } else
+               return(0.0);
+}
+
+/*
+ * prng seedfile functions
+ */
+int
+prng_check_seedfile(char *filename) {
+
+       struct stat st;
+
+       /* FIXME raceable: eg replace seed between this stat and subsequent open */
+       /* Not such a problem because we don't trust the seed file anyway */
+       if (lstat(filename, &st) == -1) {
+               /* Give up on hard errors */
+               if (errno != ENOENT)
+                       debug("WARNING: Couldn't stat random seed file \"%s\": %s",
+                          filename, strerror(errno));
+
+               return(0);
+       }
+
+       /* regular file? */
+       if (!S_ISREG(st.st_mode))
+               fatal("PRNG seedfile %.100s is not a regular file", filename);
+
+       /* mode 0600, owned by root or the current user? */
+       if (((st.st_mode & 0177) != 0) || !(st.st_uid == original_uid)) {
+               debug("WARNING: PRNG seedfile %.100s must be mode 0600, owned by uid %d",
+                        filename, getuid());
+               return(0);
+       }
+
+       return(1);
+}
+
+void
+prng_write_seedfile(void) {
+       int fd;
+       char seed[1024];
+       char filename[1024];
+       struct passwd *pw;
+
+       /* Don't bother if we have already saved a seed */
+       if (prng_seed_saved)
+               return;
+
+       setuid(original_uid);
+
+       prng_seed_saved = 1;
+
+       pw = getpwuid(original_uid);
+       if (pw == NULL)
+               fatal("Couldn't get password entry for current user (%i): %s",
+                       original_uid, strerror(errno));
+
+       /* Try to ensure that the parent directory is there */
+       snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+               _PATH_SSH_USER_DIR);
+       mkdir(filename, 0700);
+
+       snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+               SSH_PRNG_SEED_FILE);
+
+       debug("writing PRNG seed to file %.100s", filename);
+
+       RAND_bytes(seed, sizeof(seed));
+
+       /* Don't care if the seed doesn't exist */
+       prng_check_seedfile(filename);
+
+       if ((fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600)) == -1) {
+               debug("WARNING: couldn't access PRNG seedfile %.100s (%.100s)",
+                  filename, strerror(errno));
+       } else {
+               if (atomicio(write, fd, &seed, sizeof(seed)) != sizeof(seed))
+                       fatal("problem writing PRNG seedfile %.100s (%.100s)", filename,
+                                strerror(errno));
+
+               close(fd);
+       }
+}
+
+void
+prng_read_seedfile(void) {
+       int fd;
+       char seed[1024];
+       char filename[1024];
+       struct passwd *pw;
+
+       pw = getpwuid(original_uid);
+       if (pw == NULL)
+               fatal("Couldn't get password entry for current user (%i): %s",
+                       original_uid, strerror(errno));
+
+       snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+               SSH_PRNG_SEED_FILE);
+
+       debug("loading PRNG seed from file %.100s", filename);
+
+       if (!prng_check_seedfile(filename)) {
+               verbose("Random seed file not found or not valid, ignoring.");
+               return;
+       }
+
+       /* open the file and read in the seed */
+       fd = open(filename, O_RDONLY);
+       if (fd == -1)
+               fatal("could not open PRNG seedfile %.100s (%.100s)", filename,
+                       strerror(errno));
+
+       if (atomicio(read, fd, &seed, sizeof(seed)) != sizeof(seed)) {
+               verbose("invalid or short read from PRNG seedfile %.100s - ignoring",
+                       filename);
+               memset(seed, '\0', sizeof(seed));
+       }
+       close(fd);
+
+       /* stir in the seed, with estimated entropy zero */
+       RAND_add(&seed, sizeof(seed), 0.0);
+}
+
+
+/*
+ * entropy command initialisation functions
+ */
+int
+prng_read_commands(char *cmdfilename)
+{
+       FILE *f;
+       char *cp;
+       char line[1024];
+       char cmd[1024];
+       char path[256];
+       int linenum;
+       int num_cmds = 64;
+       int cur_cmd = 0;
+       double est;
+       entropy_source_t *entcmd;
+
+       f = fopen(cmdfilename, "r");
+       if (!f) {
+               fatal("couldn't read entropy commands file %.100s: %.100s",
+                   cmdfilename, strerror(errno));
+       }
+
+       entcmd = (entropy_source_t *)xmalloc(num_cmds * sizeof(entropy_source_t));
+       memset(entcmd, '\0', num_cmds * sizeof(entropy_source_t));
+
+       /* Read in file */
+       linenum = 0;
+       while (fgets(line, sizeof(line), f)) {
+               int arg;
+               char *argv;
+
+               linenum++;
+
+               /* skip leading whitespace, test for blank line or comment */
+               cp = line + strspn(line, WHITESPACE);
+               if ((*cp == 0) || (*cp == '#'))
+                       continue; /* done with this line */
+
+               /* First non-whitespace char should be double quote delimiting */
+               /* commandline */
+               if (*cp != '"') {
+                       error("bad entropy command, %.100s line %d", cmdfilename,
+                            linenum);
+                       continue;
+               }
+
+               /* first token, command args (incl. argv[0]) in double quotes */
+               cp = strtok(cp, "\"");
+               if (cp == NULL) {
+                       error("missing or bad command string, %.100s line %d -- ignored",
+                             cmdfilename, linenum);
+                       continue;
+               }
+               strlcpy(cmd, cp, sizeof(cmd));
+
+               /* second token, full command path */
+               if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
+                       error("missing command path, %.100s line %d -- ignored",
+                             cmdfilename, linenum);
+                       continue;
+               }
+
+               /* did configure mark this as dead? */
+               if (strncmp("undef", cp, 5) == 0)
+                       continue;
+
+               strlcpy(path, cp, sizeof(path));
+
+               /* third token, entropy rate estimate for this command */
+               if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
+                       error("missing entropy estimate, %.100s line %d -- ignored",
+                             cmdfilename, linenum);
+                       continue;
+               }
+               est = strtod(cp, &argv);
+
+               /* end of line */
+               if ((cp = strtok(NULL, WHITESPACE)) != NULL) {
+                       error("garbage at end of line %d in %.100s -- ignored", linenum,
+                               cmdfilename);
+                       continue;
+               }
+
+               /* save the command for debug messages */
+               entcmd[cur_cmd].cmdstring = xstrdup(cmd);
+
+               /* split the command args */
+               cp = strtok(cmd, WHITESPACE);
+               arg = 0;
+               argv = NULL;
+               do {
+                       char *s = (char*)xmalloc(strlen(cp) + 1);
+                       strncpy(s, cp, strlen(cp) + 1);
+                       entcmd[cur_cmd].args[arg] = s;
+                       arg++;
+               } while ((arg < 5) && (cp = strtok(NULL, WHITESPACE)));
+
+               if (strtok(NULL, WHITESPACE))
+                       error("ignored extra command elements (max 5), %.100s line %d",
+                             cmdfilename, linenum);
+
+               /* Copy the command path and rate estimate */
+               entcmd[cur_cmd].path = xstrdup(path);
+               entcmd[cur_cmd].rate = est;
+
+               /* Initialise other values */
+               entcmd[cur_cmd].sticky_badness = 1;
+
+               cur_cmd++;
+
+               /* If we've filled the array, reallocate it twice the size */
+               /* Do this now because even if this we're on the last command,
+                  we need another slot to mark the last entry */
+               if (cur_cmd == num_cmds) {
+                       num_cmds *= 2;
+                       entcmd = xrealloc(entcmd, num_cmds * sizeof(entropy_source_t));
+               }
+       }
+
+       /* zero the last entry */
+       memset(&entcmd[cur_cmd], '\0', sizeof(entropy_source_t));
+
+       /* trim to size */
+       entropy_sources = xrealloc(entcmd, (cur_cmd+1) * sizeof(entropy_source_t));
+
+       debug("Loaded %d entropy commands from %.100s", cur_cmd, cmdfilename);
+
+       return (cur_cmd >= MIN_ENTROPY_SOURCES);
+}
+
+/*
+ * Write a keyfile at exit
+ */
+void
+prng_seed_cleanup(void *junk)
+{
+       prng_write_seedfile();
+}
+
+/*
+ * Conditionally Seed OpenSSL's random number pool from
+ * syscalls and program output
+ */
+void
+seed_rng(void)
+{
+       mysig_t old_sigchld_handler;
+
+       if (!prng_initialised)
+               fatal("RNG not initialised");
+
+       /* Make sure some other sigchld handler doesn't reap our entropy */
+       /* commands */
+       old_sigchld_handler = mysignal(SIGCHLD, SIG_DFL);
+
+       debug("Seeded RNG with %i bytes from programs", 
+           (int)stir_from_programs());
+       debug("Seeded RNG with %i bytes from system calls", 
+           (int)stir_from_system());
+
+       if (!RAND_status())
+               fatal("Not enough entropy in RNG");
+
+       mysignal(SIGCHLD, old_sigchld_handler);
+
+       if (!RAND_status())
+               fatal("Couldn't initialise builtin random number generator -- exiting.");
+}
+
+void
+init_rng(void)
+{
+       int original_euid;
+
+       check_openssl_version();
+
+       original_uid = getuid();
+       original_euid = geteuid();
+
+       /* Read in collection commands */
+       if (!prng_read_commands(SSH_PRNG_COMMAND_FILE))
+               fatal("PRNG initialisation failed -- exiting.");
+
+       /* Set ourselves up to save a seed upon exit */
+       prng_seed_saved = 0;
+
+       /* Give up privs while reading seed file */
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+       if ((original_uid != original_euid) && (seteuid(original_uid) == -1))
+               fatal("Couldn't give up privileges");
+#else /* SAVED_IDS_WORK_WITH_SETEUID */
+       /*
+        * Propagate the privileged uid to all of our uids.
+        * Set the effective uid to the given (unprivileged) uid. 
+        */
+       if (original_uid != original_euid && (setuid(original_euid) == -1 || 
+           seteuid(original_uid) == -1))
+               fatal("Couldn't give up privileges");
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+
+       prng_read_seedfile();
+
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+       if ((original_uid != original_euid) && (seteuid(original_euid) == -1))
+               fatal("Couldn't restore privileges");
+#else /* SAVED_IDS_WORK_WITH_SETEUID */
+       /*
+        * We are unable to restore the real uid to its unprivileged value.
+        * Propagate the real uid (usually more privileged) to effective uid
+        * as well.
+        */
+       if (original_uid != original_euid && (seteuid(original_euid) == -1 || 
+           setuid(original_uid) == -1))
+               fatal("Couldn't restore privileges");
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+
+       fatal_add_cleanup(prng_seed_cleanup, NULL);
+       atexit(prng_write_seedfile);
+
+       prng_initialised = 1;
+}
+
+#endif /* defined(USE_PRNGD) || defined(RANDOM_POOL) */
diff --git a/openssh/entropy.h b/openssh/entropy.h
new file mode 100644 (file)
index 0000000..270eacb
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1999-2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _RANDOMS_H
+#define _RANDOMS_H
+
+void seed_rng(void);
+void init_rng(void);
+
+#endif /* _RANDOMS_H */
diff --git a/openssh/fixpaths b/openssh/fixpaths
new file mode 100755 (executable)
index 0000000..7e4178e
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/perl -w
+#
+# fixpaths  - substitute makefile variables into text files
+
+
+$usage = "Usage: $0 [-Dstring=replacement] [[infile] ...]\n";
+
+if (!defined(@ARGV)) { die ("$usage"); }
+
+# read in the command line and get some definitions
+while ($_=$ARGV[0], /^-/) {
+  if (/^-D/) {
+    # definition
+    shift(@ARGV);
+    if ( /-D(.*)=(.*)/ ) {
+      $def{"$1"}=$2;
+    } else {
+      die ("$usage$0: error in command line arguments.\n");
+    }
+  } else {
+    @cmd = split(//, $ARGV[0]); $opt = $cmd[1];
+    die ("$usage$0: unknown option '-$opt'\n");
+  }
+} # while parsing arguments
+
+if (!defined(%def)) {
+  die ("$0: nothing to do - no substitutions listed!\n");
+}
+
+for $f (@ARGV) {
+
+  $f =~ /(.*\/)*(.*)$/;
+
+  open(IN, "<$f")          || die ("$0: input file $f missing!\n");
+  while (<IN>) {
+    for $s (keys(%def)) {
+      s#$s#$def{$s}#;
+    } # for $s
+    print;
+  } # while <IN>
+} # for $f
+
+exit 0;
diff --git a/openssh/fixprogs b/openssh/fixprogs
new file mode 100755 (executable)
index 0000000..61840cf
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+#
+# fixprogs  - run through the list of entropy commands and
+#             score out the losers
+#
+
+$entscale = 50; # divisor for optional entropy measurement
+
+sub usage {
+  return("Usage: $0 <command file>\n");
+}
+
+if (($#ARGV == -1) || ($#ARGV>1)) {
+  die(&usage);
+}
+
+# 'undocumented' option - run ent (in second param) on the output
+if ($#ARGV==1) {
+  $entcmd=$ARGV[1]
+} else {
+  $entcmd = ""
+};
+
+$infilename = $ARGV[0];
+
+if (!open(IN, "<".$infilename)) {
+  die("Couldn't open input file");
+}
+$outfilename=$infilename.".out";
+if (!open(OUT, ">$outfilename")) {
+  die("Couldn't open output file $outfilename");
+}
+@infile=<IN>;
+
+select(OUT); $|=1; select(STDOUT);
+
+foreach (@infile) {
+  if (/^\s*\#/ || /^\s*$/) {
+    print OUT;
+    next;
+  }
+  ($cmd, $path, $est) = /^\"([^\"]+)\"\s+([\w\/_-]+)\s+([\d\.\-]+)/o;
+  @args = split(/ /, $cmd);
+   if (! ($pid = fork())) {
+     # child
+     close STDIN; close STDOUT; close STDERR;
+     open (STDIN,  "</dev/null");
+     open (STDOUT, ">/dev/null");
+     open (STDERR, ">/dev/null");
+     exec $path @args;
+     exit 1; # shouldn't be here
+   }
+   # parent
+   waitpid ($pid, 0); $ret=$? >> 8;
+
+  if ($ret != 0) {
+    $path = "undef";
+  } else {
+    if ($entcmd ne "") {
+      # now try to run ent on the command
+      $mostargs=join(" ", splice(@args,1));
+      print "Evaluating '$path $mostargs'\n";
+      @ent = qx{$path $mostargs | $entcmd -b -t};
+      @ent = grep(/^1,/, @ent);
+      ($null, $null, $rate) = split(/,/, $ent[0]);
+      $est = $rate / $entscale;                # scale the estimate back
+    }
+  }    
+  print OUT "\"$cmd\" $path $est\n";
+}
+
+close(IN);
diff --git a/openssh/getput.h b/openssh/getput.h
new file mode 100644 (file)
index 0000000..1a19d22
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Macros for storing and retrieving data in msb first and lsb first order.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: getput.h,v 1.7 2001/01/10 22:56:22 markus Exp $"); */
+
+#ifndef GETPUT_H
+#define GETPUT_H
+
+/*------------ macros for storing/extracting msb first words -------------*/
+
+#define GET_64BIT(cp) (((u_int64_t)(u_char)(cp)[0] << 56) | \
+                      ((u_int64_t)(u_char)(cp)[1] << 48) | \
+                      ((u_int64_t)(u_char)(cp)[2] << 40) | \
+                      ((u_int64_t)(u_char)(cp)[3] << 32) | \
+                      ((u_int64_t)(u_char)(cp)[4] << 24) | \
+                      ((u_int64_t)(u_char)(cp)[5] << 16) | \
+                      ((u_int64_t)(u_char)(cp)[6] << 8) | \
+                      ((u_int64_t)(u_char)(cp)[7]))
+
+#define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \
+                      ((u_long)(u_char)(cp)[1] << 16) | \
+                      ((u_long)(u_char)(cp)[2] << 8) | \
+                      ((u_long)(u_char)(cp)[3]))
+
+#define GET_16BIT(cp) (((u_long)(u_char)(cp)[0] << 8) | \
+                      ((u_long)(u_char)(cp)[1]))
+
+#define PUT_64BIT(cp, value) do { \
+  (cp)[0] = (value) >> 56; \
+  (cp)[1] = (value) >> 48; \
+  (cp)[2] = (value) >> 40; \
+  (cp)[3] = (value) >> 32; \
+  (cp)[4] = (value) >> 24; \
+  (cp)[5] = (value) >> 16; \
+  (cp)[6] = (value) >> 8; \
+  (cp)[7] = (value); } while (0)
+
+#define PUT_32BIT(cp, value) do { \
+  (cp)[0] = (value) >> 24; \
+  (cp)[1] = (value) >> 16; \
+  (cp)[2] = (value) >> 8; \
+  (cp)[3] = (value); } while (0)
+
+#define PUT_16BIT(cp, value) do { \
+  (cp)[0] = (value) >> 8; \
+  (cp)[1] = (value); } while (0)
+
+#endif                         /* GETPUT_H */
diff --git a/openssh/groupaccess.c b/openssh/groupaccess.c
new file mode 100644 (file)
index 0000000..cbfe720
--- /dev/null
@@ -0,0 +1,89 @@
+/*     $OpenBSD: groupaccess.c,v 1.4 2001/06/26 17:27:23 markus Exp $  */
+
+/*
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#include "groupaccess.h"
+#include "xmalloc.h"
+#include "match.h"
+#include "log.h"
+
+static int ngroups;
+static char *groups_byname[NGROUPS_MAX + 1];   /* +1 for base/primary group */
+
+/*
+ * Initialize group access list for user with primary (base) and
+ * supplementary groups.  Return the number of groups in the list.
+ */
+int
+ga_init(const char *user, gid_t base)
+{
+       gid_t groups_bygid[NGROUPS_MAX + 1];
+       int i, j;
+       struct group *gr;
+
+       if (ngroups > 0)
+               ga_free();
+
+       ngroups = sizeof(groups_bygid) / sizeof(gid_t);
+       if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
+               log("getgrouplist: groups list too small");
+       for (i = 0, j = 0; i < ngroups; i++)
+               if ((gr = getgrgid(groups_bygid[i])) != NULL)
+                       groups_byname[j++] = xstrdup(gr->gr_name);
+       return (ngroups = j);
+}
+
+/*
+ * Return 1 if one of user's groups is contained in groups.
+ * Return 0 otherwise.  Use match_pattern() for string comparison.
+ */
+int
+ga_match(char * const *groups, int n)
+{
+       int i, j;
+
+       for (i = 0; i < ngroups; i++)
+               for (j = 0; j < n; j++)
+                       if (match_pattern(groups_byname[i], groups[j]))
+                               return 1;
+       return 0;
+}
+
+/*
+ * Free memory allocated for group access list.
+ */
+void
+ga_free(void)
+{
+       int i;
+
+       if (ngroups > 0) {
+               for (i = 0; i < ngroups; i++)
+                       xfree(groups_byname[i]);
+               ngroups = 0;
+       }
+}
diff --git a/openssh/groupaccess.h b/openssh/groupaccess.h
new file mode 100644 (file)
index 0000000..ede4805
--- /dev/null
@@ -0,0 +1,36 @@
+/*     $OpenBSD: groupaccess.h,v 1.4 2001/06/26 17:27:23 markus Exp $  */
+
+/*
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GROUPACCESS_H
+#define GROUPACCESS_H
+
+#include <grp.h>
+
+int     ga_init(const char *, gid_t);
+int     ga_match(char * const *, int);
+void    ga_free(void);
+
+#endif
diff --git a/openssh/hostfile.c b/openssh/hostfile.c
new file mode 100644 (file)
index 0000000..eeed920
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for manipulating the known hosts files.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * Copyright (c) 1999, 2000 Markus Friedl.  All rights reserved.
+ * Copyright (c) 1999 Niels Provos.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: hostfile.c,v 1.28 2001/06/25 08:25:37 markus Exp $");
+
+#include "packet.h"
+#include "match.h"
+#include "key.h"
+#include "hostfile.h"
+#include "log.h"
+
+/*
+ * Parses an RSA (number of bits, e, n) or DSA key from a string.  Moves the
+ * pointer over the key.  Skips any whitespace at the beginning and at end.
+ */
+
+static int
+hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
+{
+       char *cp;
+
+       /* Skip leading whitespace. */
+       for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
+               ;
+
+       if (key_read(ret, &cp) != 1)
+               return 0;
+
+       /* Skip trailing whitespace. */
+       for (; *cp == ' ' || *cp == '\t'; cp++)
+               ;
+
+       /* Return results. */
+       *cpp = cp;
+       *bitsp = key_size(ret);
+       return 1;
+}
+
+int
+auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n)
+{
+       Key *k = key_new(KEY_RSA1);
+       int ret = hostfile_read_key(cpp, bitsp, k);
+       BN_copy(e, k->rsa->e);
+       BN_copy(n, k->rsa->n);
+       key_free(k);
+       return ret;
+}
+
+static int
+hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
+{
+       if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
+               return 1;
+       if (bits != BN_num_bits(key->rsa->n)) {
+               log("Warning: %s, line %d: keysize mismatch for host %s: "
+                   "actual %d vs. announced %d.",
+                   filename, linenum, host, BN_num_bits(key->rsa->n), bits);
+               log("Warning: replace %d with %d in %s, line %d.",
+                   bits, BN_num_bits(key->rsa->n), filename, linenum);
+       }
+       return 1;
+}
+
+/*
+ * Checks whether the given host (which must be in all lowercase) is already
+ * in the list of our known hosts. Returns HOST_OK if the host is known and
+ * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
+ * if the host is known but used to have a different host key.
+ */
+
+HostStatus
+check_host_in_hostfile(const char *filename, const char *host, Key *key,
+    Key *found, int *numret)
+{
+       FILE *f;
+       char line[8192];
+       int linenum = 0;
+       u_int kbits;
+       char *cp, *cp2;
+       HostStatus end_return;
+
+       debug3("check_host_in_hostfile: filename %s", filename);
+       if (key == NULL)
+               fatal("no key to look up");
+       /* Open the file containing the list of known hosts. */
+       f = fopen(filename, "r");
+       if (!f)
+               return HOST_NEW;
+
+       /*
+        * Return value when the loop terminates.  This is set to
+        * HOST_CHANGED if we have seen a different key for the host and have
+        * not found the proper one.
+        */
+       end_return = HOST_NEW;
+
+       /* Go through the file. */
+       while (fgets(line, sizeof(line), f)) {
+               cp = line;
+               linenum++;
+
+               /* Skip any leading whitespace, comments and empty lines. */
+               for (; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '#' || *cp == '\n')
+                       continue;
+
+               /* Find the end of the host name portion. */
+               for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
+                       ;
+
+               /* Check if the host name matches. */
+               if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1)
+                       continue;
+
+               /* Got a match.  Skip host name. */
+               cp = cp2;
+
+               /*
+                * Extract the key from the line.  This will skip any leading
+                * whitespace.  Ignore badly formatted lines.
+                */
+               if (!hostfile_read_key(&cp, &kbits, found))
+                       continue;
+               if (!hostfile_check_key(kbits, found, host, filename, linenum))
+                       continue;
+
+               if (numret != NULL)
+                       *numret = linenum;
+
+               /* Check if the current key is the same as the given key. */
+               if (key_equal(key, found)) {
+                       /* Ok, they match. */
+                       debug3("check_host_in_hostfile: match line %d", linenum);
+                       fclose(f);
+                       return HOST_OK;
+               }
+               /*
+                * They do not match.  We will continue to go through the
+                * file; however, we note that we will not return that it is
+                * new.
+                */
+               end_return = HOST_CHANGED;
+       }
+       /* Clear variables and close the file. */
+       fclose(f);
+
+       /*
+        * Return either HOST_NEW or HOST_CHANGED, depending on whether we
+        * saw a different key for the host.
+        */
+       return end_return;
+}
+
+/*
+ * Appends an entry to the host file.  Returns false if the entry could not
+ * be appended.
+ */
+
+int
+add_host_to_hostfile(const char *filename, const char *host, Key *key)
+{
+       FILE *f;
+       int success = 0;
+       if (key == NULL)
+               return 1;       /* XXX ? */
+       f = fopen(filename, "a");
+       if (!f)
+               return 0;
+       fprintf(f, "%s ", host);
+       if (key_write(key, f)) {
+               success = 1;
+       } else {
+               error("add_host_to_hostfile: saving key in %s failed", filename);
+       }
+       fprintf(f, "\n");
+       fclose(f);
+       return success;
+}
diff --git a/openssh/hostfile.h b/openssh/hostfile.h
new file mode 100644 (file)
index 0000000..05ef691
--- /dev/null
@@ -0,0 +1,26 @@
+/*     $OpenBSD: hostfile.h,v 1.9 2001/06/26 17:27:23 markus Exp $     */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+#ifndef HOSTFILE_H
+#define HOSTFILE_H
+
+typedef enum {
+       HOST_OK, HOST_NEW, HOST_CHANGED
+}       HostStatus;
+
+HostStatus
+check_host_in_hostfile(const char *, const char *, Key *, Key *, int *);
+int     add_host_to_hostfile(const char *, const char *, Key *);
+int     auth_rsa_read_key(char **, u_int *, BIGNUM *, BIGNUM *);
+
+#endif
diff --git a/openssh/includes.h b/openssh/includes.h
new file mode 100644 (file)
index 0000000..f9cf9c7
--- /dev/null
@@ -0,0 +1,106 @@
+/*     $OpenBSD: includes.h,v 1.15 2001/06/08 15:25:40 markus Exp $    */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file includes most of the needed system headers.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+#define RCSID(msg) \
+static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
+
+#include "config.h"
+
+#include "openbsd-compat/bsd-nextstep.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <dirent.h>
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+#ifndef HAVE_GETOPT_OPTRESET
+#define getopt(ac, av, o)  BSDgetopt(ac, av, o)
+#endif
+#ifdef HAVE_BSTRING_H
+# include <bstring.h>
+#endif
+#if defined(HAVE_GLOB_H) && defined(GLOB_HAS_ALTDIRFUNC) && \
+    defined(GLOB_HAS_GL_MATCHC)
+# include <glob.h>
+#endif
+#ifdef HAVE_NETGROUP_H
+# include <netgroup.h>
+#endif
+#if defined(HAVE_NETDB_H)
+# include <netdb.h>
+#endif
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_BSDTTY_H
+# include <sys/bsdtty.h>
+#endif
+#ifdef HAVE_TTYENT_H
+# include <ttyent.h>
+#endif
+#ifdef USE_PAM
+# include <security/pam_appl.h>
+#endif
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#else
+# ifdef HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+# endif
+#endif
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h>
+#endif
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#endif
+#include "version.h"
+#include "openbsd-compat/openbsd-compat.h"
+#include "openbsd-compat/bsd-cygwin_util.h"
+#include "entropy.h"
+
+#endif /* INCLUDES_H */
diff --git a/openssh/install-sh b/openssh/install-sh
new file mode 100755 (executable)
index 0000000..e9de238
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/openssh/kex.c b/openssh/kex.c
new file mode 100644 (file)
index 0000000..1a412ce
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: kex.c,v 1.36 2001/06/25 08:25:37 markus Exp $");
+
+#include <openssl/crypto.h>
+
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "packet.h"
+#include "compat.h"
+#include "cipher.h"
+#include "kex.h"
+#include "key.h"
+#include "log.h"
+#include "mac.h"
+#include "match.h"
+#include "dispatch.h"
+
+#define KEX_COOKIE_LEN 16
+
+/* prototype */
+static void kex_kexinit_finish(Kex *);
+static void kex_choose_conf(Kex *);
+
+/* put algorithm proposal into buffer */
+static void
+kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
+{
+       u_int32_t rand = 0;
+       int i;
+
+       buffer_clear(b);
+       for (i = 0; i < KEX_COOKIE_LEN; i++) {
+               if (i % 4 == 0)
+                       rand = arc4random();
+               buffer_put_char(b, rand & 0xff);
+               rand >>= 8;
+       }
+       for (i = 0; i < PROPOSAL_MAX; i++)
+               buffer_put_cstring(b, proposal[i]);
+       buffer_put_char(b, 0);                  /* first_kex_packet_follows */
+       buffer_put_int(b, 0);                   /* uint32 reserved */
+}
+
+/* parse buffer and return algorithm proposal */
+static char **
+kex_buf2prop(Buffer *raw)
+{
+       Buffer b;
+       int i;
+       char **proposal;
+
+       proposal = xmalloc(PROPOSAL_MAX * sizeof(char *));
+
+       buffer_init(&b);
+       buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
+       /* skip cookie */
+       for (i = 0; i < KEX_COOKIE_LEN; i++)
+               buffer_get_char(&b);
+       /* extract kex init proposal strings */
+       for (i = 0; i < PROPOSAL_MAX; i++) {
+               proposal[i] = buffer_get_string(&b,NULL);
+               debug2("kex_parse_kexinit: %s", proposal[i]);
+       }
+       /* first kex follows / reserved */
+       i = buffer_get_char(&b);
+       debug2("kex_parse_kexinit: first_kex_follows %d ", i);
+       i = buffer_get_int(&b);
+       debug2("kex_parse_kexinit: reserved %d ", i);
+       buffer_free(&b);
+       return proposal;
+}
+
+static void
+kex_prop_free(char **proposal)
+{
+       int i;
+
+       for (i = 0; i < PROPOSAL_MAX; i++)
+               xfree(proposal[i]);
+       xfree(proposal);
+}
+
+static void
+kex_protocol_error(int type, int plen, void *ctxt)
+{
+       error("Hm, kex protocol error: type %d plen %d", type, plen);
+}
+
+static void
+kex_clear_dispatch(void)
+{
+       int i;
+
+       /* Numbers 30-49 are used for kex packets */
+       for (i = 30; i <= 49; i++)
+               dispatch_set(i, &kex_protocol_error);
+}
+
+void
+kex_finish(Kex *kex)
+{
+       int plen;
+
+       kex_clear_dispatch();
+
+       packet_start(SSH2_MSG_NEWKEYS);
+       packet_send();
+       /* packet_write_wait(); */
+       debug("SSH2_MSG_NEWKEYS sent");
+
+       debug("waiting for SSH2_MSG_NEWKEYS");
+       packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
+       debug("SSH2_MSG_NEWKEYS received");
+
+       kex->done = 1;
+       buffer_clear(&kex->peer);
+       /* buffer_clear(&kex->my); */
+       kex->flags &= ~KEX_INIT_SENT;
+       xfree(kex->name);
+       kex->name = NULL;
+}
+
+void
+kex_send_kexinit(Kex *kex)
+{
+       if (kex == NULL) {
+               error("kex_send_kexinit: no kex, cannot rekey");
+               return;
+       }
+       if (kex->flags & KEX_INIT_SENT) {
+               debug("KEX_INIT_SENT");
+               return;
+       }
+       kex->done = 0;
+       packet_start(SSH2_MSG_KEXINIT);
+       packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
+       packet_send();
+       debug("SSH2_MSG_KEXINIT sent");
+       kex->flags |= KEX_INIT_SENT;
+}
+
+void
+kex_input_kexinit(int type, int plen, void *ctxt)
+{
+       char *ptr;
+       int dlen;
+       int i;
+       Kex *kex = (Kex *)ctxt;
+
+       debug("SSH2_MSG_KEXINIT received");
+       if (kex == NULL)
+               fatal("kex_input_kexinit: no kex, cannot rekey");
+
+       ptr = packet_get_raw(&dlen);
+       buffer_append(&kex->peer, ptr, dlen);
+
+       /* discard packet */
+       for (i = 0; i < KEX_COOKIE_LEN; i++)
+               packet_get_char();
+       for (i = 0; i < PROPOSAL_MAX; i++)
+               xfree(packet_get_string(NULL));
+       packet_get_char();
+       packet_get_int();
+       packet_done();
+
+       kex_kexinit_finish(kex);
+}
+
+Kex *
+kex_setup(char *proposal[PROPOSAL_MAX])
+{
+       Kex *kex;
+
+       kex = xmalloc(sizeof(*kex));
+       memset(kex, 0, sizeof(*kex));
+       buffer_init(&kex->peer);
+       buffer_init(&kex->my);
+       kex_prop2buf(&kex->my, proposal);
+       kex->done = 0;
+
+       kex_send_kexinit(kex);                                  /* we start */
+       kex_clear_dispatch();
+       dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
+
+       return kex;
+}
+
+static void
+kex_kexinit_finish(Kex *kex)
+{
+       if (!(kex->flags & KEX_INIT_SENT))
+               kex_send_kexinit(kex);
+
+       kex_choose_conf(kex);
+
+       switch(kex->kex_type) {
+       case DH_GRP1_SHA1:
+               kexdh(kex);
+               break;
+       case DH_GEX_SHA1:
+               kexgex(kex);
+               break;
+       default:
+               fatal("Unsupported key exchange %d", kex->kex_type);
+       }
+}
+
+static void
+choose_enc(Enc *enc, char *client, char *server)
+{
+       char *name = match_list(client, server, NULL);
+       if (name == NULL)
+               fatal("no matching cipher found: client %s server %s", client, server);
+       enc->cipher = cipher_by_name(name);
+       if (enc->cipher == NULL)
+               fatal("matching cipher is not supported: %s", name);
+       enc->name = name;
+       enc->enabled = 0;
+       enc->iv = NULL;
+       enc->key = NULL;
+}
+static void
+choose_mac(Mac *mac, char *client, char *server)
+{
+       char *name = match_list(client, server, NULL);
+       if (name == NULL)
+               fatal("no matching mac found: client %s server %s", client, server);
+       if (mac_init(mac, name) < 0)
+               fatal("unsupported mac %s", name);
+       /* truncate the key */
+       if (datafellows & SSH_BUG_HMAC)
+               mac->key_len = 16;
+       mac->name = name;
+       mac->key = NULL;
+       mac->enabled = 0;
+}
+static void
+choose_comp(Comp *comp, char *client, char *server)
+{
+       char *name = match_list(client, server, NULL);
+       if (name == NULL)
+               fatal("no matching comp found: client %s server %s", client, server);
+       if (strcmp(name, "zlib") == 0) {
+               comp->type = 1;
+       } else if (strcmp(name, "none") == 0) {
+               comp->type = 0;
+       } else {
+               fatal("unsupported comp %s", name);
+       }
+       comp->name = name;
+}
+static void
+choose_kex(Kex *k, char *client, char *server)
+{
+       k->name = match_list(client, server, NULL);
+       if (k->name == NULL)
+               fatal("no kex alg");
+       if (strcmp(k->name, KEX_DH1) == 0) {
+               k->kex_type = DH_GRP1_SHA1;
+       } else if (strcmp(k->name, KEX_DHGEX) == 0) {
+               k->kex_type = DH_GEX_SHA1;
+       } else
+               fatal("bad kex alg %s", k->name);
+}
+static void
+choose_hostkeyalg(Kex *k, char *client, char *server)
+{
+       char *hostkeyalg = match_list(client, server, NULL);
+       if (hostkeyalg == NULL)
+               fatal("no hostkey alg");
+       k->hostkey_type = key_type_from_name(hostkeyalg);
+       if (k->hostkey_type == KEY_UNSPEC)
+               fatal("bad hostkey alg '%s'", hostkeyalg);
+       xfree(hostkeyalg);
+}
+
+static void
+kex_choose_conf(Kex *kex)
+{
+       Newkeys *newkeys;
+       char **my, **peer;
+       char **cprop, **sprop;
+       int nenc, nmac, ncomp;
+       int mode;
+       int ctos;                               /* direction: if true client-to-server */
+       int need;
+
+       my   = kex_buf2prop(&kex->my);
+       peer = kex_buf2prop(&kex->peer);
+
+       if (kex->server) {
+               cprop=peer;
+               sprop=my;
+       } else {
+               cprop=my;
+               sprop=peer;
+       }
+
+       /* Algorithm Negotiation */
+       for (mode = 0; mode < MODE_MAX; mode++) {
+               newkeys = xmalloc(sizeof(*newkeys));
+               memset(newkeys, 0, sizeof(*newkeys));
+               kex->newkeys[mode] = newkeys;
+               ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
+               nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
+               nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
+               ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
+               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("kex: %s %s %s %s",
+                   ctos ? "client->server" : "server->client",
+                   newkeys->enc.name,
+                   newkeys->mac.name,
+                   newkeys->comp.name);
+       }
+       choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
+       choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
+           sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
+       need = 0;
+       for (mode = 0; mode < MODE_MAX; mode++) {
+               newkeys = kex->newkeys[mode];
+               if (need < newkeys->enc.cipher->key_len)
+                       need = newkeys->enc.cipher->key_len;
+               if (need < newkeys->enc.cipher->block_size)
+                       need = newkeys->enc.cipher->block_size;
+               if (need < newkeys->mac.key_len)
+                       need = newkeys->mac.key_len;
+       }
+       /* XXX need runden? */
+       kex->we_need = need;
+
+       kex_prop_free(my);
+       kex_prop_free(peer);
+}
+
+static u_char *
+derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
+{
+       Buffer b;
+       EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+       char c = id;
+       int have;
+       int mdsz = evp_md->md_size;
+       u_char *digest = xmalloc(roundup(need, mdsz));
+
+       buffer_init(&b);
+       buffer_put_bignum2(&b, shared_secret);
+
+       /* K1 = HASH(K || H || "A" || session_id) */
+       EVP_DigestInit(&md, evp_md);
+       if (!(datafellows & SSH_BUG_DERIVEKEY))
+               EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+       EVP_DigestUpdate(&md, hash, mdsz);
+       EVP_DigestUpdate(&md, &c, 1);
+       EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
+       EVP_DigestFinal(&md, digest, NULL);
+
+       /*
+        * expand key:
+        * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
+        * Key = K1 || K2 || ... || Kn
+        */
+       for (have = mdsz; need > have; have += mdsz) {
+               EVP_DigestInit(&md, evp_md);
+               if (!(datafellows & SSH_BUG_DERIVEKEY))
+                       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+               EVP_DigestUpdate(&md, hash, mdsz);
+               EVP_DigestUpdate(&md, digest, have);
+               EVP_DigestFinal(&md, digest + have, NULL);
+       }
+       buffer_free(&b);
+#ifdef DEBUG_KEX
+       fprintf(stderr, "key '%c'== ", c);
+       dump_digest("key", digest, need);
+#endif
+       return digest;
+}
+
+Newkeys *current_keys[MODE_MAX];
+
+#define NKEYS  6
+void
+kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret)
+{
+       u_char *keys[NKEYS];
+       int i, mode, ctos;
+
+       for (i = 0; i < NKEYS; i++)
+               keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret);
+
+       debug("kex_derive_keys");
+       for (mode = 0; mode < MODE_MAX; mode++) {
+               current_keys[mode] = kex->newkeys[mode];
+               kex->newkeys[mode] = NULL;
+               ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
+               current_keys[mode]->enc.iv  = keys[ctos ? 0 : 1];
+               current_keys[mode]->enc.key = keys[ctos ? 2 : 3];
+               current_keys[mode]->mac.key = keys[ctos ? 4 : 5];
+       }
+}
+
+Newkeys *
+kex_get_newkeys(int mode)
+{
+       Newkeys *ret;
+
+       ret = current_keys[mode];
+       current_keys[mode] = NULL;
+       return ret;
+}
+
+#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
+void
+dump_digest(char *msg, u_char *digest, int len)
+{
+       int i;
+
+       fprintf(stderr, "%s\n", msg);
+       for (i = 0; i< len; i++){
+               fprintf(stderr, "%02x", digest[i]);
+               if (i%32 == 31)
+                       fprintf(stderr, "\n");
+               else if (i%8 == 7)
+                       fprintf(stderr, " ");
+       }
+       fprintf(stderr, "\n");
+}
+#endif
diff --git a/openssh/kex.h b/openssh/kex.h
new file mode 100644 (file)
index 0000000..fe33921
--- /dev/null
@@ -0,0 +1,130 @@
+/*     $OpenBSD: kex.h,v 1.26 2001/06/26 17:27:23 markus Exp $ */
+
+/*
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef KEX_H
+#define KEX_H
+
+#include <openssl/evp.h>
+#include "buffer.h"
+#include "cipher.h"
+#include "key.h"
+
+#define        KEX_DH1         "diffie-hellman-group1-sha1"
+#define        KEX_DHGEX       "diffie-hellman-group-exchange-sha1"
+
+enum kex_init_proposals {
+       PROPOSAL_KEX_ALGS,
+       PROPOSAL_SERVER_HOST_KEY_ALGS,
+       PROPOSAL_ENC_ALGS_CTOS,
+       PROPOSAL_ENC_ALGS_STOC,
+       PROPOSAL_MAC_ALGS_CTOS,
+       PROPOSAL_MAC_ALGS_STOC,
+       PROPOSAL_COMP_ALGS_CTOS,
+       PROPOSAL_COMP_ALGS_STOC,
+       PROPOSAL_LANG_CTOS,
+       PROPOSAL_LANG_STOC,
+       PROPOSAL_MAX
+};
+
+enum kex_modes {
+       MODE_IN,
+       MODE_OUT,
+       MODE_MAX
+};
+
+enum kex_exchange {
+       DH_GRP1_SHA1,
+       DH_GEX_SHA1
+};
+
+#define KEX_INIT_SENT  0x0001
+
+typedef struct Kex Kex;
+typedef struct Mac Mac;
+typedef struct Comp Comp;
+typedef struct Enc Enc;
+typedef struct Newkeys Newkeys;
+
+struct Enc {
+       char    *name;
+       Cipher  *cipher;
+       int     enabled;
+       u_char  *key;
+       u_char  *iv;
+};
+struct Mac {
+       char    *name;
+       int     enabled;
+       EVP_MD  *md;
+       int     mac_len;
+       u_char  *key;
+       int     key_len;
+};
+struct Comp {
+       int     type;
+       int     enabled;
+       char    *name;
+};
+struct Newkeys {
+       Enc     enc;
+       Mac     mac;
+       Comp    comp;
+};
+struct Kex {
+       u_char  *session_id;
+       int     session_id_len;
+       Newkeys *newkeys[MODE_MAX];
+       int     we_need;
+       int     server;
+       char    *name;
+       int     hostkey_type;
+       int     kex_type;
+       Buffer  my;
+       Buffer  peer;
+       int     done;
+       int     flags;
+       char    *client_version_string;
+       char    *server_version_string;
+       int     (*verify_host_key)(Key *);
+       Key     *(*load_host_key)(int);
+};
+
+Kex    *kex_setup(char *[PROPOSAL_MAX]);
+void    kex_finish(Kex *);
+
+void    kex_send_kexinit(Kex *);
+void    kex_input_kexinit(int, int, void *);
+void    kex_derive_keys(Kex *, u_char *, BIGNUM *);
+
+void    kexdh(Kex *);
+void    kexgex(Kex *);
+
+Newkeys *kex_get_newkeys(int);
+
+#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
+void   dump_digest(char *, u_char *, int);
+#endif
+
+#endif
diff --git a/openssh/kexdh.c b/openssh/kexdh.c
new file mode 100644 (file)
index 0000000..b850a1a
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: kexdh.c,v 1.7 2001/09/17 19:27:15 stevesk Exp $");
+
+#include <openssl/crypto.h>
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+
+static u_char *
+kex_dh_hash(
+    char *client_version_string,
+    char *server_version_string,
+    char *ckexinit, int ckexinitlen,
+    char *skexinit, int skexinitlen,
+    u_char *serverhostkeyblob, int sbloblen,
+    BIGNUM *client_dh_pub,
+    BIGNUM *server_dh_pub,
+    BIGNUM *shared_secret)
+{
+       Buffer b;
+       static u_char digest[EVP_MAX_MD_SIZE];
+       EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+
+       buffer_init(&b);
+       buffer_put_cstring(&b, client_version_string);
+       buffer_put_cstring(&b, server_version_string);
+
+       /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+       buffer_put_int(&b, ckexinitlen+1);
+       buffer_put_char(&b, SSH2_MSG_KEXINIT);
+       buffer_append(&b, ckexinit, ckexinitlen);
+       buffer_put_int(&b, skexinitlen+1);
+       buffer_put_char(&b, SSH2_MSG_KEXINIT);
+       buffer_append(&b, skexinit, skexinitlen);
+
+       buffer_put_string(&b, serverhostkeyblob, sbloblen);
+       buffer_put_bignum2(&b, client_dh_pub);
+       buffer_put_bignum2(&b, server_dh_pub);
+       buffer_put_bignum2(&b, shared_secret);
+
+#ifdef DEBUG_KEX
+       buffer_dump(&b);
+#endif
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+       EVP_DigestFinal(&md, digest, NULL);
+
+       buffer_free(&b);
+
+#ifdef DEBUG_KEX
+       dump_digest("hash", digest, evp_md->md_size);
+#endif
+       return digest;
+}
+
+/* client */
+
+static void
+kexdh_client(Kex *kex)
+{
+       BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+       DH *dh;
+       Key *server_host_key;
+       u_char *server_host_key_blob = NULL, *signature = NULL;
+       u_char *kbuf, *hash;
+       u_int klen, kout, slen, sbloblen;
+       int dlen, plen;
+
+       /* generate and send 'e', client DH public key */
+       dh = dh_new_group1();
+       dh_gen_key(dh, kex->we_need * 8);
+       packet_start(SSH2_MSG_KEXDH_INIT);
+       packet_put_bignum2(dh->pub_key);
+       packet_send();
+
+       debug("sending SSH2_MSG_KEXDH_INIT");
+#ifdef DEBUG_KEXDH
+       DHparams_print_fp(stderr, dh);
+       fprintf(stderr, "pub= ");
+       BN_print_fp(stderr, dh->pub_key);
+       fprintf(stderr, "\n");
+#endif
+
+       debug("expecting SSH2_MSG_KEXDH_REPLY");
+       packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
+
+       /* key, cert */
+       server_host_key_blob = packet_get_string(&sbloblen);
+       server_host_key = key_from_blob(server_host_key_blob, sbloblen);
+       if (server_host_key == NULL)
+               fatal("cannot decode server_host_key_blob");
+
+       if (kex->verify_host_key == NULL)
+               fatal("cannot verify server_host_key");
+       if (kex->verify_host_key(server_host_key) == -1)
+               fatal("server_host_key verification failed");
+
+       /* DH paramter f, server public DH key */
+       dh_server_pub = BN_new();
+       if (dh_server_pub == NULL)
+               fatal("dh_server_pub == NULL");
+       packet_get_bignum2(dh_server_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+       fprintf(stderr, "dh_server_pub= ");
+       BN_print_fp(stderr, dh_server_pub);
+       fprintf(stderr, "\n");
+       debug("bits %d", BN_num_bits(dh_server_pub));
+#endif
+
+       /* signed H */
+       signature = packet_get_string(&slen);
+       packet_done();
+
+       if (!dh_pub_is_valid(dh, dh_server_pub))
+               packet_disconnect("bad server public DH value");
+
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       kout = DH_compute_key(kbuf, dh_server_pub, dh);
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       shared_secret = BN_new();
+       BN_bin2bn(kbuf, kout, shared_secret);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       /* calc and verify H */
+       hash = kex_dh_hash(
+           kex->client_version_string,
+           kex->server_version_string,
+           buffer_ptr(&kex->my), buffer_len(&kex->my),
+           buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+           server_host_key_blob, sbloblen,
+           dh->pub_key,
+           dh_server_pub,
+           shared_secret
+       );
+       xfree(server_host_key_blob);
+       BN_free(dh_server_pub);
+       DH_free(dh);
+
+       if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
+               fatal("key_verify failed for server_host_key");
+       key_free(server_host_key);
+       xfree(signature);
+
+       /* save session id */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = 20;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       kex_derive_keys(kex, hash, shared_secret);
+       BN_clear_free(shared_secret);
+       kex_finish(kex);
+}
+
+/* server */
+
+static void
+kexdh_server(Kex *kex)
+{
+       BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+       DH *dh;
+       Key *server_host_key;
+       u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+       u_int sbloblen, klen, kout;
+       int dlen, slen, plen;
+
+       /* generate server DH public key */
+       dh = dh_new_group1();
+       dh_gen_key(dh, kex->we_need * 8);
+
+       debug("expecting SSH2_MSG_KEXDH_INIT");
+       packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT);
+
+       if (kex->load_host_key == NULL)
+               fatal("Cannot load hostkey");
+       server_host_key = kex->load_host_key(kex->hostkey_type);
+       if (server_host_key == NULL)
+               fatal("Unsupported hostkey type %d", kex->hostkey_type);
+
+       /* key, cert */
+       dh_client_pub = BN_new();
+       if (dh_client_pub == NULL)
+               fatal("dh_client_pub == NULL");
+       packet_get_bignum2(dh_client_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+       fprintf(stderr, "dh_client_pub= ");
+       BN_print_fp(stderr, dh_client_pub);
+       fprintf(stderr, "\n");
+       debug("bits %d", BN_num_bits(dh_client_pub));
+#endif
+
+#ifdef DEBUG_KEXDH
+       DHparams_print_fp(stderr, dh);
+       fprintf(stderr, "pub= ");
+       BN_print_fp(stderr, dh->pub_key);
+       fprintf(stderr, "\n");
+#endif
+       if (!dh_pub_is_valid(dh, dh_client_pub))
+               packet_disconnect("bad client public DH value");
+
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       kout = DH_compute_key(kbuf, dh_client_pub, dh);
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       shared_secret = BN_new();
+       BN_bin2bn(kbuf, kout, shared_secret);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
+
+       /* calc H */
+       hash = kex_dh_hash(
+           kex->client_version_string,
+           kex->server_version_string,
+           buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+           buffer_ptr(&kex->my), buffer_len(&kex->my),
+           server_host_key_blob, sbloblen,
+           dh_client_pub,
+           dh->pub_key,
+           shared_secret
+       );
+       BN_free(dh_client_pub);
+
+       /* save session id := H */
+       /* XXX hashlen depends on KEX */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = 20;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       /* sign H */
+       /* XXX hashlen depends on KEX */
+       key_sign(server_host_key, &signature, &slen, hash, 20);
+
+       /* destroy_sensitive_data(); */
+
+       /* send server hostkey, DH pubkey 'f' and singed H */
+       packet_start(SSH2_MSG_KEXDH_REPLY);
+       packet_put_string(server_host_key_blob, sbloblen);
+       packet_put_bignum2(dh->pub_key);        /* f */
+       packet_put_string(signature, slen);
+       packet_send();
+
+       xfree(signature);
+       xfree(server_host_key_blob);
+       /* have keys, free DH */
+       DH_free(dh);
+
+       kex_derive_keys(kex, hash, shared_secret);
+       BN_clear_free(shared_secret);
+       kex_finish(kex);
+}
+
+void
+kexdh(Kex *kex)
+{
+       if (kex->server)
+               kexdh_server(kex);
+       else
+               kexdh_client(kex);
+}
diff --git a/openssh/kexgex.c b/openssh/kexgex.c
new file mode 100644 (file)
index 0000000..f06f2c3
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2000 Niels Provos.  All rights reserved.
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: kexgex.c,v 1.9 2001/09/17 19:27:15 stevesk Exp $");
+
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#include "compat.h"
+
+static u_char *
+kexgex_hash(
+    char *client_version_string,
+    char *server_version_string,
+    char *ckexinit, int ckexinitlen,
+    char *skexinit, int skexinitlen,
+    u_char *serverhostkeyblob, int sbloblen,
+    int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
+    BIGNUM *client_dh_pub,
+    BIGNUM *server_dh_pub,
+    BIGNUM *shared_secret)
+{
+       Buffer b;
+       static u_char digest[EVP_MAX_MD_SIZE];
+       EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+
+       buffer_init(&b);
+       buffer_put_cstring(&b, client_version_string);
+       buffer_put_cstring(&b, server_version_string);
+
+       /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+       buffer_put_int(&b, ckexinitlen+1);
+       buffer_put_char(&b, SSH2_MSG_KEXINIT);
+       buffer_append(&b, ckexinit, ckexinitlen);
+       buffer_put_int(&b, skexinitlen+1);
+       buffer_put_char(&b, SSH2_MSG_KEXINIT);
+       buffer_append(&b, skexinit, skexinitlen);
+
+       buffer_put_string(&b, serverhostkeyblob, sbloblen);
+       if (min == -1 || max == -1)
+               buffer_put_int(&b, wantbits);
+       else {
+               buffer_put_int(&b, min);
+               buffer_put_int(&b, wantbits);
+               buffer_put_int(&b, max);
+       }
+       buffer_put_bignum2(&b, prime);
+       buffer_put_bignum2(&b, gen);
+       buffer_put_bignum2(&b, client_dh_pub);
+       buffer_put_bignum2(&b, server_dh_pub);
+       buffer_put_bignum2(&b, shared_secret);
+
+#ifdef DEBUG_KEXDH
+       buffer_dump(&b);
+#endif
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+       EVP_DigestFinal(&md, digest, NULL);
+
+       buffer_free(&b);
+
+#ifdef DEBUG_KEXDH
+       dump_digest("hash", digest, evp_md->md_size);
+#endif
+       return digest;
+}
+
+/* client */
+
+static void
+kexgex_client(Kex *kex)
+{
+       BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+       BIGNUM *p = NULL, *g = NULL;
+       Key *server_host_key;
+       u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+       u_int klen, kout, slen, sbloblen;
+       int dlen, plen, min, max, nbits;
+       DH *dh;
+
+       nbits = dh_estimate(kex->we_need * 8);
+
+       if (datafellows & SSH_OLD_DHGEX) {
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
+
+               /* Old GEX request */
+               packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
+               packet_put_int(nbits);
+               min = DH_GRP_MIN;
+               max = DH_GRP_MAX;
+       } else {
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
+
+               /* New GEX request */
+               min = DH_GRP_MIN;
+               max = DH_GRP_MAX;
+               packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
+               packet_put_int(min);
+               packet_put_int(nbits);
+               packet_put_int(max);
+       }
+#ifdef DEBUG_KEXDH
+       fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
+           min, nbits, max);
+#endif
+       packet_send();
+
+       debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
+       packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
+
+       if ((p = BN_new()) == NULL)
+               fatal("BN_new");
+       packet_get_bignum2(p, &dlen);
+       if ((g = BN_new()) == NULL)
+               fatal("BN_new");
+       packet_get_bignum2(g, &dlen);
+       packet_done();
+
+       if (BN_num_bits(p) < min || BN_num_bits(p) > max)
+               fatal("DH_GEX group out of range: %d !< %d !< %d",
+                   min, BN_num_bits(p), max);
+
+       dh = dh_new_group(g, p);
+       dh_gen_key(dh, kex->we_need * 8);
+
+#ifdef DEBUG_KEXDH
+       DHparams_print_fp(stderr, dh);
+       fprintf(stderr, "pub= ");
+       BN_print_fp(stderr, dh->pub_key);
+       fprintf(stderr, "\n");
+#endif
+
+       debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
+       /* generate and send 'e', client DH public key */
+       packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
+       packet_put_bignum2(dh->pub_key);
+       packet_send();
+
+       debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
+       packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
+
+       /* key, cert */
+       server_host_key_blob = packet_get_string(&sbloblen);
+       server_host_key = key_from_blob(server_host_key_blob, sbloblen);
+       if (server_host_key == NULL)
+               fatal("cannot decode server_host_key_blob");
+
+       if (kex->verify_host_key == NULL)
+               fatal("cannot verify server_host_key");
+       if (kex->verify_host_key(server_host_key) == -1)
+               fatal("server_host_key verification failed");
+
+       /* DH paramter f, server public DH key */
+       dh_server_pub = BN_new();
+       if (dh_server_pub == NULL)
+               fatal("dh_server_pub == NULL");
+       packet_get_bignum2(dh_server_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+       fprintf(stderr, "dh_server_pub= ");
+       BN_print_fp(stderr, dh_server_pub);
+       fprintf(stderr, "\n");
+       debug("bits %d", BN_num_bits(dh_server_pub));
+#endif
+
+       /* signed H */
+       signature = packet_get_string(&slen);
+       packet_done();
+
+       if (!dh_pub_is_valid(dh, dh_server_pub))
+               packet_disconnect("bad server public DH value");
+
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       kout = DH_compute_key(kbuf, dh_server_pub, dh);
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       shared_secret = BN_new();
+       BN_bin2bn(kbuf, kout, shared_secret);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       if (datafellows & SSH_OLD_DHGEX)
+               min = max = -1;
+
+       /* calc and verify H */
+       hash = kexgex_hash(
+           kex->client_version_string,
+           kex->server_version_string,
+           buffer_ptr(&kex->my), buffer_len(&kex->my),
+           buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+           server_host_key_blob, sbloblen,
+           min, nbits, max,
+           dh->p, dh->g,
+           dh->pub_key,
+           dh_server_pub,
+           shared_secret
+       );
+       /* have keys, free DH */
+       DH_free(dh);
+       xfree(server_host_key_blob);
+       BN_free(dh_server_pub);
+
+       if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
+               fatal("key_verify failed for server_host_key");
+       key_free(server_host_key);
+       xfree(signature);
+
+       /* save session id */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = 20;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+       kex_derive_keys(kex, hash, shared_secret);
+       BN_clear_free(shared_secret);
+
+       kex_finish(kex);
+}
+
+/* server */
+
+static void
+kexgex_server(Kex *kex)
+{
+       BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+       Key *server_host_key;
+       DH *dh = dh;
+       u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+       u_int sbloblen, klen, kout;
+       int min = -1, max = -1, nbits = -1, type, plen, dlen, slen;
+
+       if (kex->load_host_key == NULL)
+               fatal("Cannot load hostkey");
+       server_host_key = kex->load_host_key(kex->hostkey_type);
+       if (server_host_key == NULL)
+               fatal("Unsupported hostkey type %d", kex->hostkey_type);
+
+       type = packet_read(&plen);
+       switch(type){
+       case SSH2_MSG_KEX_DH_GEX_REQUEST:
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
+               min = packet_get_int();
+               nbits = packet_get_int();
+               max = packet_get_int();
+               min = MAX(DH_GRP_MIN, min);
+               max = MIN(DH_GRP_MAX, max);
+               break;
+       case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
+               nbits = packet_get_int();
+               min = DH_GRP_MIN;
+               max = DH_GRP_MAX;
+               /* unused for old GEX */
+               break;
+       default:
+               fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
+       }
+       packet_done();
+
+       if (max < min || nbits < min || max < nbits)
+               fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
+                   min, nbits, max);
+
+       dh = choose_dh(min, nbits, max);
+       if (dh == NULL)
+               packet_disconnect("Protocol error: no matching DH grp found");
+
+       debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
+       packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
+       packet_put_bignum2(dh->p);
+       packet_put_bignum2(dh->g);
+       packet_send();
+
+       /* flush */
+       packet_write_wait();
+
+       /* Compute our exchange value in parallel with the client */
+       dh_gen_key(dh, kex->we_need * 8);
+
+       debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
+       packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT);
+
+       /* key, cert */
+       dh_client_pub = BN_new();
+       if (dh_client_pub == NULL)
+               fatal("dh_client_pub == NULL");
+       packet_get_bignum2(dh_client_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+       fprintf(stderr, "dh_client_pub= ");
+       BN_print_fp(stderr, dh_client_pub);
+       fprintf(stderr, "\n");
+       debug("bits %d", BN_num_bits(dh_client_pub));
+#endif
+
+#ifdef DEBUG_KEXDH
+       DHparams_print_fp(stderr, dh);
+       fprintf(stderr, "pub= ");
+       BN_print_fp(stderr, dh->pub_key);
+       fprintf(stderr, "\n");
+#endif
+       if (!dh_pub_is_valid(dh, dh_client_pub))
+               packet_disconnect("bad client public DH value");
+
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       kout = DH_compute_key(kbuf, dh_client_pub, dh);
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       shared_secret = BN_new();
+       BN_bin2bn(kbuf, kout, shared_secret);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
+
+       if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
+               min = max = -1;
+
+       /* calc H */                    /* XXX depends on 'kex' */
+       hash = kexgex_hash(
+           kex->client_version_string,
+           kex->server_version_string,
+           buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+           buffer_ptr(&kex->my), buffer_len(&kex->my),
+           server_host_key_blob, sbloblen,
+           min, nbits, max,
+           dh->p, dh->g,
+           dh_client_pub,
+           dh->pub_key,
+           shared_secret
+       );
+       BN_free(dh_client_pub);
+
+       /* save session id := H */
+       /* XXX hashlen depends on KEX */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = 20;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       /* sign H */
+       /* XXX hashlen depends on KEX */
+       key_sign(server_host_key, &signature, &slen, hash, 20);
+
+       /* destroy_sensitive_data(); */
+
+       /* send server hostkey, DH pubkey 'f' and singed H */
+       debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
+       packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
+       packet_put_string(server_host_key_blob, sbloblen);
+       packet_put_bignum2(dh->pub_key);        /* f */
+       packet_put_string(signature, slen);
+       packet_send();
+       xfree(signature);
+       xfree(server_host_key_blob);
+       /* have keys, free DH */
+       DH_free(dh);
+
+       kex_derive_keys(kex, hash, shared_secret);
+       BN_clear_free(shared_secret);
+
+       kex_finish(kex);
+}
+
+void
+kexgex(Kex *kex)
+{
+       if (kex->server)
+               kexgex_server(kex);
+       else
+               kexgex_client(kex);
+}
diff --git a/openssh/key.c b/openssh/key.c
new file mode 100644 (file)
index 0000000..57df5b9
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ * read_bignum():
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: key.c,v 1.33 2001/10/04 14:34:16 markus Exp $");
+
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "rsa.h"
+#include "ssh-dss.h"
+#include "ssh-rsa.h"
+#include "uuencode.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "log.h"
+
+Key *
+key_new(int type)
+{
+       Key *k;
+       RSA *rsa;
+       DSA *dsa;
+       k = xmalloc(sizeof(*k));
+       k->type = type;
+       k->flags = 0;
+       k->dsa = NULL;
+       k->rsa = NULL;
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+               rsa = RSA_new();
+               rsa->n = BN_new();
+               rsa->e = BN_new();
+               k->rsa = rsa;
+               break;
+       case KEY_DSA:
+               dsa = DSA_new();
+               dsa->p = BN_new();
+               dsa->q = BN_new();
+               dsa->g = BN_new();
+               dsa->pub_key = BN_new();
+               k->dsa = dsa;
+               break;
+       case KEY_UNSPEC:
+               break;
+       default:
+               fatal("key_new: bad key type %d", k->type);
+               break;
+       }
+       return k;
+}
+Key *
+key_new_private(int type)
+{
+       Key *k = key_new(type);
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+               k->rsa->d = BN_new();
+               k->rsa->iqmp = BN_new();
+               k->rsa->q = BN_new();
+               k->rsa->p = BN_new();
+               k->rsa->dmq1 = BN_new();
+               k->rsa->dmp1 = BN_new();
+               break;
+       case KEY_DSA:
+               k->dsa->priv_key = BN_new();
+               break;
+       case KEY_UNSPEC:
+               break;
+       default:
+               break;
+       }
+       return k;
+}
+void
+key_free(Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+               if (k->rsa != NULL)
+                       RSA_free(k->rsa);
+               k->rsa = NULL;
+               break;
+       case KEY_DSA:
+               if (k->dsa != NULL)
+                       DSA_free(k->dsa);
+               k->dsa = NULL;
+               break;
+       case KEY_UNSPEC:
+               break;
+       default:
+               fatal("key_free: bad key type %d", k->type);
+               break;
+       }
+       xfree(k);
+}
+int
+key_equal(Key *a, Key *b)
+{
+       if (a == NULL || b == NULL || a->type != b->type)
+               return 0;
+       switch (a->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+               return a->rsa != NULL && b->rsa != NULL &&
+                   BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
+                   BN_cmp(a->rsa->n, b->rsa->n) == 0;
+               break;
+       case KEY_DSA:
+               return a->dsa != NULL && b->dsa != NULL &&
+                   BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
+                   BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
+                   BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
+                   BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
+               break;
+       default:
+               fatal("key_equal: bad key type %d", a->type);
+               break;
+       }
+       return 0;
+}
+
+static u_char*
+key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
+{
+       EVP_MD *md = NULL;
+       EVP_MD_CTX ctx;
+       u_char *blob = NULL;
+       u_char *retval = NULL;
+       int len = 0;
+       int nlen, elen;
+
+       *dgst_raw_length = 0;
+
+       switch (dgst_type) {
+       case SSH_FP_MD5:
+               md = EVP_md5();
+               break;
+       case SSH_FP_SHA1:
+               md = EVP_sha1();
+               break;
+       default:
+               fatal("key_fingerprint_raw: bad digest type %d",
+                   dgst_type);
+       }
+       switch (k->type) {
+       case KEY_RSA1:
+               nlen = BN_num_bytes(k->rsa->n);
+               elen = BN_num_bytes(k->rsa->e);
+               len = nlen + elen;
+               blob = xmalloc(len);
+               BN_bn2bin(k->rsa->n, blob);
+               BN_bn2bin(k->rsa->e, blob + nlen);
+               break;
+       case KEY_DSA:
+       case KEY_RSA:
+               key_to_blob(k, &blob, &len);
+               break;
+       case KEY_UNSPEC:
+               return retval;
+               break;
+       default:
+               fatal("key_fingerprint_raw: bad key type %d", k->type);
+               break;
+       }
+       if (blob != NULL) {
+               retval = xmalloc(EVP_MAX_MD_SIZE);
+               EVP_DigestInit(&ctx, md);
+               EVP_DigestUpdate(&ctx, blob, len);
+               EVP_DigestFinal(&ctx, retval, NULL);
+               *dgst_raw_length = md->md_size;
+               memset(blob, 0, len);
+               xfree(blob);
+       } else {
+               fatal("key_fingerprint_raw: blob is null");
+       }
+       return retval;
+}
+
+static char*
+key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
+{
+       char *retval;
+       int i;
+
+       retval = xmalloc(dgst_raw_len * 3 + 1);
+       retval[0] = '\0';
+       for(i = 0; i < dgst_raw_len; i++) {
+               char hex[4];
+               snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
+               strlcat(retval, hex, dgst_raw_len * 3);
+       }
+       retval[(dgst_raw_len * 3) - 1] = '\0';
+       return retval;
+}
+
+static char*
+key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
+{
+       char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
+       char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
+           'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
+       u_int i, j = 0, rounds, seed = 1;
+       char *retval;
+
+       rounds = (dgst_raw_len / 2) + 1;
+       retval = xmalloc(sizeof(char) * (rounds*6));
+       retval[j++] = 'x';
+       for (i = 0; i < rounds; i++) {
+               u_int idx0, idx1, idx2, idx3, idx4;
+               if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
+                       idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
+                           seed) % 6;
+                       idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
+                       idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
+                           (seed / 6)) % 6;
+                       retval[j++] = vowels[idx0];
+                       retval[j++] = consonants[idx1];
+                       retval[j++] = vowels[idx2];
+                       if ((i + 1) < rounds) {
+                               idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
+                               idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
+                               retval[j++] = consonants[idx3];
+                               retval[j++] = '-';
+                               retval[j++] = consonants[idx4];
+                               seed = ((seed * 5) +
+                                   ((((u_int)(dgst_raw[2 * i])) * 7) +
+                                   ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
+                       }
+               } else {
+                       idx0 = seed % 6;
+                       idx1 = 16;
+                       idx2 = seed / 6;
+                       retval[j++] = vowels[idx0];
+                       retval[j++] = consonants[idx1];
+                       retval[j++] = vowels[idx2];
+               }
+       }
+       retval[j++] = 'x';
+       retval[j++] = '\0';
+       return retval;
+}
+
+char*
+key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
+{
+       char *retval = NULL;
+       u_char *dgst_raw;
+       size_t dgst_raw_len;
+       
+       dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
+       if (!dgst_raw)
+               fatal("key_fingerprint: null from key_fingerprint_raw()");
+       switch(dgst_rep) {
+       case SSH_FP_HEX:
+               retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
+               break;
+       case SSH_FP_BUBBLEBABBLE:
+               retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
+               break;
+       default:
+               fatal("key_fingerprint_ex: bad digest representation %d",
+                   dgst_rep);
+               break;
+       }
+       memset(dgst_raw, 0, dgst_raw_len);
+       xfree(dgst_raw);
+       return retval;
+}
+
+/*
+ * Reads a multiple-precision integer in decimal from the buffer, and advances
+ * the pointer.  The integer must already be initialized.  This function is
+ * permitted to modify the buffer.  This leaves *cpp to point just beyond the
+ * last processed (and maybe modified) character.  Note that this may modify
+ * the buffer containing the number.
+ */
+static int
+read_bignum(char **cpp, BIGNUM * value)
+{
+       char *cp = *cpp;
+       int old;
+
+       /* Skip any leading whitespace. */
+       for (; *cp == ' ' || *cp == '\t'; cp++)
+               ;
+
+       /* Check that it begins with a decimal digit. */
+       if (*cp < '0' || *cp > '9')
+               return 0;
+
+       /* Save starting position. */
+       *cpp = cp;
+
+       /* Move forward until all decimal digits skipped. */
+       for (; *cp >= '0' && *cp <= '9'; cp++)
+               ;
+
+       /* Save the old terminating character, and replace it by \0. */
+       old = *cp;
+       *cp = 0;
+
+       /* Parse the number. */
+       if (BN_dec2bn(&value, *cpp) == 0)
+               return 0;
+
+       /* Restore old terminating character. */
+       *cp = old;
+
+       /* Move beyond the number and return success. */
+       *cpp = cp;
+       return 1;
+}
+static int
+write_bignum(FILE *f, BIGNUM *num)
+{
+       char *buf = BN_bn2dec(num);
+       if (buf == NULL) {
+               error("write_bignum: BN_bn2dec() failed");
+               return 0;
+       }
+       fprintf(f, " %s", buf);
+       OPENSSL_free(buf);
+       return 1;
+}
+
+/* returns 1 ok, -1 error */
+int
+key_read(Key *ret, char **cpp)
+{
+       Key *k;
+       int success = -1;
+       char *cp, *space;
+       int len, n, type;
+       u_int bits;
+       u_char *blob;
+
+       cp = *cpp;
+
+       switch(ret->type) {
+       case KEY_RSA1:
+               /* Get number of bits. */
+               if (*cp < '0' || *cp > '9')
+                       return -1;      /* Bad bit count... */
+               for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
+                       bits = 10 * bits + *cp - '0';
+               if (bits == 0)
+                       return -1;
+               *cpp = cp;
+               /* Get public exponent, public modulus. */
+               if (!read_bignum(cpp, ret->rsa->e))
+                       return -1;
+               if (!read_bignum(cpp, ret->rsa->n))
+                       return -1;
+               success = 1;
+               break;
+       case KEY_UNSPEC:
+       case KEY_RSA:
+       case KEY_DSA:
+               space = strchr(cp, ' ');
+               if (space == NULL) {
+                       debug3("key_read: no space");
+                       return -1;
+               }
+               *space = '\0';
+               type = key_type_from_name(cp);
+               *space = ' ';
+               if (type == KEY_UNSPEC) {
+                       debug3("key_read: no key found");
+                       return -1;
+               }
+               cp = space+1;
+               if (*cp == '\0') {
+                       debug3("key_read: short string");
+                       return -1;
+               }
+               if (ret->type == KEY_UNSPEC) {
+                       ret->type = type;
+               } else if (ret->type != type) {
+                       /* is a key, but different type */
+                       debug3("key_read: type mismatch");
+                       return -1;
+               }
+               len = 2*strlen(cp);
+               blob = xmalloc(len);
+               n = uudecode(cp, blob, len);
+               if (n < 0) {
+                       error("key_read: uudecode %s failed", cp);
+                       return -1;
+               }
+               k = key_from_blob(blob, n);
+               if (k == NULL) {
+                       error("key_read: key_from_blob %s failed", cp);
+                       return -1;
+               }
+               xfree(blob);
+               if (k->type != type) {
+                       error("key_read: type mismatch: encoding error");
+                       key_free(k);
+                       return -1;
+               }
+/*XXXX*/
+               if (ret->type == KEY_RSA) {
+                       if (ret->rsa != NULL)
+                               RSA_free(ret->rsa);
+                       ret->rsa = k->rsa;
+                       k->rsa = NULL;
+                       success = 1;
+#ifdef DEBUG_PK
+                       RSA_print_fp(stderr, ret->rsa, 8);
+#endif
+               } else {
+                       if (ret->dsa != NULL)
+                               DSA_free(ret->dsa);
+                       ret->dsa = k->dsa;
+                       k->dsa = NULL;
+                       success = 1;
+#ifdef DEBUG_PK
+                       DSA_print_fp(stderr, ret->dsa, 8);
+#endif
+               }
+/*XXXX*/
+               if (success != 1)
+                       break;
+               key_free(k);
+               /* advance cp: skip whitespace and data */
+               while (*cp == ' ' || *cp == '\t')
+                       cp++;
+               while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+                       cp++;
+               *cpp = cp;
+               break;
+       default:
+               fatal("key_read: bad key type: %d", ret->type);
+               break;
+       }
+       return success;
+}
+int
+key_write(Key *key, FILE *f)
+{
+       int success = 0;
+       u_int bits = 0;
+
+       if (key->type == KEY_RSA1 && key->rsa != NULL) {
+               /* size of modulus 'n' */
+               bits = BN_num_bits(key->rsa->n);
+               fprintf(f, "%u", bits);
+               if (write_bignum(f, key->rsa->e) &&
+                   write_bignum(f, key->rsa->n)) {
+                       success = 1;
+               } else {
+                       error("key_write: failed for RSA key");
+               }
+       } else if ((key->type == KEY_DSA && key->dsa != NULL) ||
+           (key->type == KEY_RSA && key->rsa != NULL)) {
+               int len, n;
+               u_char *blob, *uu;
+               key_to_blob(key, &blob, &len);
+               uu = xmalloc(2*len);
+               n = uuencode(blob, len, uu, 2*len);
+               if (n > 0) {
+                       fprintf(f, "%s %s", key_ssh_name(key), uu);
+                       success = 1;
+               }
+               xfree(blob);
+               xfree(uu);
+       }
+       return success;
+}
+char *
+key_type(Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA1:
+               return "RSA1";
+               break;
+       case KEY_RSA:
+               return "RSA";
+               break;
+       case KEY_DSA:
+               return "DSA";
+               break;
+       }
+       return "unknown";
+}
+char *
+key_ssh_name(Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA:
+               return "ssh-rsa";
+               break;
+       case KEY_DSA:
+               return "ssh-dss";
+               break;
+       }
+       return "ssh-unknown";
+}
+u_int
+key_size(Key *k){
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+               return BN_num_bits(k->rsa->n);
+               break;
+       case KEY_DSA:
+               return BN_num_bits(k->dsa->p);
+               break;
+       }
+       return 0;
+}
+
+static RSA *
+rsa_generate_private_key(u_int bits)
+{
+       RSA *private;
+       private = RSA_generate_key(bits, 35, NULL, NULL);
+       if (private == NULL)
+               fatal("rsa_generate_private_key: key generation failed.");
+       return private;
+}
+
+static DSA*
+dsa_generate_private_key(u_int bits)
+{
+       DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
+       if (private == NULL)
+               fatal("dsa_generate_private_key: DSA_generate_parameters failed");
+       if (!DSA_generate_key(private))
+               fatal("dsa_generate_private_key: DSA_generate_key failed.");
+       if (private == NULL)
+               fatal("dsa_generate_private_key: NULL.");
+       return private;
+}
+
+Key *
+key_generate(int type, u_int bits)
+{
+       Key *k = key_new(KEY_UNSPEC);
+       switch (type) {
+       case KEY_DSA:
+               k->dsa = dsa_generate_private_key(bits);
+               break;
+       case KEY_RSA:
+       case KEY_RSA1:
+               k->rsa = rsa_generate_private_key(bits);
+               break;
+       default:
+               fatal("key_generate: unknown type %d", type);
+       }
+       k->type = type;
+       return k;
+}
+
+Key *
+key_from_private(Key *k)
+{
+       Key *n = NULL;
+       switch (k->type) {
+       case KEY_DSA:
+               n = key_new(k->type);
+               BN_copy(n->dsa->p, k->dsa->p);
+               BN_copy(n->dsa->q, k->dsa->q);
+               BN_copy(n->dsa->g, k->dsa->g);
+               BN_copy(n->dsa->pub_key, k->dsa->pub_key);
+               break;
+       case KEY_RSA:
+       case KEY_RSA1:
+               n = key_new(k->type);
+               BN_copy(n->rsa->n, k->rsa->n);
+               BN_copy(n->rsa->e, k->rsa->e);
+               break;
+       default:
+               fatal("key_from_private: unknown type %d", k->type);
+               break;
+       }
+       return n;
+}
+
+int
+key_type_from_name(char *name)
+{
+       if (strcmp(name, "rsa1") == 0){
+               return KEY_RSA1;
+       } else if (strcmp(name, "rsa") == 0){
+               return KEY_RSA;
+       } else if (strcmp(name, "dsa") == 0){
+               return KEY_DSA;
+       } else if (strcmp(name, "ssh-rsa") == 0){
+               return KEY_RSA;
+       } else if (strcmp(name, "ssh-dss") == 0){
+               return KEY_DSA;
+       }
+       debug2("key_type_from_name: unknown key type '%s'", name);
+       return KEY_UNSPEC;
+}
+
+int
+key_names_valid2(const char *names)
+{
+       char *s, *cp, *p;
+
+       if (names == NULL || strcmp(names, "") == 0)
+               return 0;
+       s = cp = xstrdup(names);
+       for ((p = strsep(&cp, ",")); p && *p != '\0';
+            (p = strsep(&cp, ","))) {
+               switch (key_type_from_name(p)) {
+               case KEY_RSA1:
+               case KEY_UNSPEC:
+                       xfree(s);
+                       return 0;
+               }
+       }
+       debug3("key names ok: [%s]", names);
+       xfree(s);
+       return 1;
+}
+
+Key *
+key_from_blob(u_char *blob, int blen)
+{
+       Buffer b;
+       char *ktype;
+       int rlen, type;
+       Key *key = NULL;
+
+#ifdef DEBUG_PK
+       dump_base64(stderr, blob, blen);
+#endif
+       buffer_init(&b);
+       buffer_append(&b, blob, blen);
+       ktype = buffer_get_string(&b, NULL);
+       type = key_type_from_name(ktype);
+
+       switch(type){
+       case KEY_RSA:
+               key = key_new(type);
+               buffer_get_bignum2(&b, key->rsa->e);
+               buffer_get_bignum2(&b, key->rsa->n);
+#ifdef DEBUG_PK
+               RSA_print_fp(stderr, key->rsa, 8);
+#endif
+               break;
+       case KEY_DSA:
+               key = key_new(type);
+               buffer_get_bignum2(&b, key->dsa->p);
+               buffer_get_bignum2(&b, key->dsa->q);
+               buffer_get_bignum2(&b, key->dsa->g);
+               buffer_get_bignum2(&b, key->dsa->pub_key);
+#ifdef DEBUG_PK
+               DSA_print_fp(stderr, key->dsa, 8);
+#endif
+               break;
+       case KEY_UNSPEC:
+               key = key_new(type);
+               break;
+       default:
+               error("key_from_blob: cannot handle type %s", ktype);
+               break;
+       }
+       rlen = buffer_len(&b);
+       if (key != NULL && rlen != 0)
+               error("key_from_blob: remaining bytes in key blob %d", rlen);
+       xfree(ktype);
+       buffer_free(&b);
+       return key;
+}
+
+int
+key_to_blob(Key *key, u_char **blobp, u_int *lenp)
+{
+       Buffer b;
+       int len;
+       u_char *buf;
+
+       if (key == NULL) {
+               error("key_to_blob: key == NULL");
+               return 0;
+       }
+       buffer_init(&b);
+       switch(key->type){
+       case KEY_DSA:
+               buffer_put_cstring(&b, key_ssh_name(key));
+               buffer_put_bignum2(&b, key->dsa->p);
+               buffer_put_bignum2(&b, key->dsa->q);
+               buffer_put_bignum2(&b, key->dsa->g);
+               buffer_put_bignum2(&b, key->dsa->pub_key);
+               break;
+       case KEY_RSA:
+               buffer_put_cstring(&b, key_ssh_name(key));
+               buffer_put_bignum2(&b, key->rsa->e);
+               buffer_put_bignum2(&b, key->rsa->n);
+               break;
+       default:
+               error("key_to_blob: unsupported key type %d", key->type);
+               buffer_free(&b);
+               return 0;
+       }
+       len = buffer_len(&b);
+       buf = xmalloc(len);
+       memcpy(buf, buffer_ptr(&b), len);
+       memset(buffer_ptr(&b), 0, len);
+       buffer_free(&b);
+       if (lenp != NULL)
+               *lenp = len;
+       if (blobp != NULL)
+               *blobp = buf;
+       return len;
+}
+
+int
+key_sign(
+    Key *key,
+    u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       switch(key->type){
+       case KEY_DSA:
+               return ssh_dss_sign(key, sigp, lenp, data, datalen);
+               break;
+       case KEY_RSA:
+               return ssh_rsa_sign(key, sigp, lenp, data, datalen);
+               break;
+       default:
+               error("key_sign: illegal key type %d", key->type);
+               return -1;
+               break;
+       }
+}
+
+int
+key_verify(
+    Key *key,
+    u_char *signature, int signaturelen,
+    u_char *data, int datalen)
+{
+       if (signaturelen == 0)
+               return -1;
+
+       switch(key->type){
+       case KEY_DSA:
+               return ssh_dss_verify(key, signature, signaturelen, data, datalen);
+               break;
+       case KEY_RSA:
+               return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
+               break;
+       default:
+               error("key_verify: illegal key type %d", key->type);
+               return -1;
+               break;
+       }
+}
diff --git a/openssh/key.h b/openssh/key.h
new file mode 100644 (file)
index 0000000..00eebb7
--- /dev/null
@@ -0,0 +1,80 @@
+/*     $OpenBSD: key.h,v 1.17 2001/09/17 19:27:15 stevesk Exp $        */
+
+/*
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef KEY_H
+#define KEY_H
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+
+typedef struct Key Key;
+enum types {
+       KEY_RSA1,
+       KEY_RSA,
+       KEY_DSA,
+       KEY_UNSPEC
+};
+enum fp_type {
+       SSH_FP_SHA1,
+       SSH_FP_MD5
+};
+enum fp_rep {
+       SSH_FP_HEX,
+       SSH_FP_BUBBLEBABBLE
+};
+
+/* key is stored in external hardware */
+#define KEY_FLAG_EXT           0x0001
+
+struct Key {
+       int      type;
+       int      flags;
+       RSA     *rsa;
+       DSA     *dsa;
+};
+
+Key    *key_new(int);
+Key    *key_new_private(int);
+void    key_free(Key *);
+int     key_equal(Key *, Key *);
+char   *key_fingerprint(Key *, enum fp_type, enum fp_rep);
+char   *key_type(Key *);
+int     key_write(Key *, FILE *);
+int     key_read(Key *, char **);
+u_int   key_size(Key *);
+
+Key    *key_generate(int, u_int);
+Key    *key_from_private(Key *);
+int     key_type_from_name(char *);
+
+Key    *key_from_blob(u_char *, int);
+int     key_to_blob(Key *, u_char **, u_int *);
+char   *key_ssh_name(Key *);
+int     key_names_valid2(const char *);
+
+int     key_sign(Key *, u_char **, int *, u_char *, int);
+int     key_verify(Key *, u_char *, int, u_char *, int);
+
+#endif
diff --git a/openssh/log.c b/openssh/log.c
new file mode 100644 (file)
index 0000000..39bc8b5
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: log.c,v 1.18 2001/06/26 17:27:23 markus Exp $");
+
+#include "log.h"
+#include "xmalloc.h"
+
+#include <syslog.h>
+
+static LogLevel log_level = SYSLOG_LEVEL_INFO;
+static int log_on_stderr = 1;
+static int log_facility = LOG_AUTH;
+static char *argv0;
+
+extern char *__progname;
+
+/* textual representation of log-facilities/levels */
+
+static struct {
+       const char *name;
+       SyslogFacility val;
+} log_facilities[] = {
+       { "DAEMON",     SYSLOG_FACILITY_DAEMON },
+       { "USER",       SYSLOG_FACILITY_USER },
+       { "AUTH",       SYSLOG_FACILITY_AUTH },
+#ifdef LOG_AUTHPRIV
+       { "AUTHPRIV",   SYSLOG_FACILITY_AUTHPRIV },
+#endif
+       { "LOCAL0",     SYSLOG_FACILITY_LOCAL0 },
+       { "LOCAL1",     SYSLOG_FACILITY_LOCAL1 },
+       { "LOCAL2",     SYSLOG_FACILITY_LOCAL2 },
+       { "LOCAL3",     SYSLOG_FACILITY_LOCAL3 },
+       { "LOCAL4",     SYSLOG_FACILITY_LOCAL4 },
+       { "LOCAL5",     SYSLOG_FACILITY_LOCAL5 },
+       { "LOCAL6",     SYSLOG_FACILITY_LOCAL6 },
+       { "LOCAL7",     SYSLOG_FACILITY_LOCAL7 },
+       { NULL, 0 }
+};
+
+static struct {
+       const char *name;
+       LogLevel val;
+} log_levels[] =
+{
+       { "QUIET",      SYSLOG_LEVEL_QUIET },
+       { "FATAL",      SYSLOG_LEVEL_FATAL },
+       { "ERROR",      SYSLOG_LEVEL_ERROR },
+       { "INFO",       SYSLOG_LEVEL_INFO },
+       { "VERBOSE",    SYSLOG_LEVEL_VERBOSE },
+       { "DEBUG",      SYSLOG_LEVEL_DEBUG1 },
+       { "DEBUG1",     SYSLOG_LEVEL_DEBUG1 },
+       { "DEBUG2",     SYSLOG_LEVEL_DEBUG2 },
+       { "DEBUG3",     SYSLOG_LEVEL_DEBUG3 },
+       { NULL, 0 }
+};
+
+static void     do_log(LogLevel level, const char *fmt, va_list args);
+
+SyslogFacility
+log_facility_number(char *name)
+{
+       int i;
+       if (name != NULL)
+               for (i = 0; log_facilities[i].name; i++)
+                       if (strcasecmp(log_facilities[i].name, name) == 0)
+                               return log_facilities[i].val;
+       return (SyslogFacility) - 1;
+}
+
+LogLevel
+log_level_number(char *name)
+{
+       int i;
+       if (name != NULL)
+               for (i = 0; log_levels[i].name; i++)
+                       if (strcasecmp(log_levels[i].name, name) == 0)
+                               return log_levels[i].val;
+       return (LogLevel) - 1;
+}
+/* Fatal messages.  This function never returns. */
+
+void
+fatal(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_FATAL, fmt, args);
+       va_end(args);
+       fatal_cleanup();
+}
+
+/* Error messages that should be logged. */
+
+void
+error(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_ERROR, fmt, args);
+       va_end(args);
+}
+
+/* Log this message (information that usually should go to the log). */
+
+void
+log(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_INFO, fmt, args);
+       va_end(args);
+}
+
+/* More detailed messages (information that does not need to go to the log). */
+
+void
+verbose(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
+       va_end(args);
+}
+
+/* Debugging messages that should not be logged during normal operation. */
+
+void
+debug(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
+       va_end(args);
+}
+
+void
+debug2(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
+       va_end(args);
+}
+
+void
+debug3(const char *fmt,...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
+       va_end(args);
+}
+
+/* Fatal cleanup */
+
+struct fatal_cleanup {
+       struct fatal_cleanup *next;
+       void (*proc) (void *);
+       void *context;
+};
+
+static struct fatal_cleanup *fatal_cleanups = NULL;
+
+/* Registers a cleanup function to be called by fatal() before exiting. */
+
+void
+fatal_add_cleanup(void (*proc) (void *), void *context)
+{
+       struct fatal_cleanup *cu;
+
+       cu = xmalloc(sizeof(*cu));
+       cu->proc = proc;
+       cu->context = context;
+       cu->next = fatal_cleanups;
+       fatal_cleanups = cu;
+}
+
+/* Removes a cleanup frunction to be called at fatal(). */
+
+void
+fatal_remove_cleanup(void (*proc) (void *context), void *context)
+{
+       struct fatal_cleanup **cup, *cu;
+
+       for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
+               cu = *cup;
+               if (cu->proc == proc && cu->context == context) {
+                       *cup = cu->next;
+                       xfree(cu);
+                       return;
+               }
+       }
+       fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx",
+           (u_long) proc, (u_long) context);
+}
+
+/* Cleanup and exit */
+void
+fatal_cleanup(void)
+{
+       struct fatal_cleanup *cu, *next_cu;
+       static int called = 0;
+
+       if (called)
+               exit(255);
+       called = 1;
+       /* Call cleanup functions. */
+       for (cu = fatal_cleanups; cu; cu = next_cu) {
+               next_cu = cu->next;
+               debug("Calling cleanup 0x%lx(0x%lx)",
+                     (u_long) cu->proc, (u_long) cu->context);
+               (*cu->proc) (cu->context);
+       }
+       exit(255);
+}
+
+
+/*
+ * Initialize the log.
+ */
+
+void
+log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
+{
+       argv0 = av0;
+
+       switch (level) {
+       case SYSLOG_LEVEL_QUIET:
+       case SYSLOG_LEVEL_FATAL:
+       case SYSLOG_LEVEL_ERROR:
+       case SYSLOG_LEVEL_INFO:
+       case SYSLOG_LEVEL_VERBOSE:
+       case SYSLOG_LEVEL_DEBUG1:
+       case SYSLOG_LEVEL_DEBUG2:
+       case SYSLOG_LEVEL_DEBUG3:
+               log_level = level;
+               break;
+       default:
+               fprintf(stderr, "Unrecognized internal syslog level code %d\n",
+                   (int) level);
+               exit(1);
+       }
+
+       log_on_stderr = on_stderr;
+       if (on_stderr)
+               return;
+
+       switch (facility) {
+       case SYSLOG_FACILITY_DAEMON:
+               log_facility = LOG_DAEMON;
+               break;
+       case SYSLOG_FACILITY_USER:
+               log_facility = LOG_USER;
+               break;
+       case SYSLOG_FACILITY_AUTH:
+               log_facility = LOG_AUTH;
+               break;
+#ifdef LOG_AUTHPRIV
+       case SYSLOG_FACILITY_AUTHPRIV:
+               log_facility = LOG_AUTHPRIV;
+               break;
+#endif
+       case SYSLOG_FACILITY_LOCAL0:
+               log_facility = LOG_LOCAL0;
+               break;
+       case SYSLOG_FACILITY_LOCAL1:
+               log_facility = LOG_LOCAL1;
+               break;
+       case SYSLOG_FACILITY_LOCAL2:
+               log_facility = LOG_LOCAL2;
+               break;
+       case SYSLOG_FACILITY_LOCAL3:
+               log_facility = LOG_LOCAL3;
+               break;
+       case SYSLOG_FACILITY_LOCAL4:
+               log_facility = LOG_LOCAL4;
+               break;
+       case SYSLOG_FACILITY_LOCAL5:
+               log_facility = LOG_LOCAL5;
+               break;
+       case SYSLOG_FACILITY_LOCAL6:
+               log_facility = LOG_LOCAL6;
+               break;
+       case SYSLOG_FACILITY_LOCAL7:
+               log_facility = LOG_LOCAL7;
+               break;
+       default:
+               fprintf(stderr,
+                   "Unrecognized internal syslog facility code %d\n",
+                   (int) facility);
+               exit(1);
+       }
+}
+
+#define MSGBUFSIZ 1024
+
+static void
+do_log(LogLevel level, const char *fmt, va_list args)
+{
+       char msgbuf[MSGBUFSIZ];
+       char fmtbuf[MSGBUFSIZ];
+       char *txt = NULL;
+       int pri = LOG_INFO;
+
+       if (level > log_level)
+               return;
+
+       switch (level) {
+       case SYSLOG_LEVEL_FATAL:
+               if (!log_on_stderr)
+                       txt = "fatal";
+               pri = LOG_CRIT;
+               break;
+       case SYSLOG_LEVEL_ERROR:
+               if (!log_on_stderr)
+                       txt = "error";
+               pri = LOG_ERR;
+               break;
+       case SYSLOG_LEVEL_INFO:
+               pri = LOG_INFO;
+               break;
+       case SYSLOG_LEVEL_VERBOSE:
+               pri = LOG_INFO;
+               break;
+       case SYSLOG_LEVEL_DEBUG1:
+               txt = "debug1";
+               pri = LOG_DEBUG;
+               break;
+       case SYSLOG_LEVEL_DEBUG2:
+               txt = "debug2";
+               pri = LOG_DEBUG;
+               break;
+       case SYSLOG_LEVEL_DEBUG3:
+               txt = "debug3";
+               pri = LOG_DEBUG;
+               break;
+       default:
+               txt = "internal error";
+               pri = LOG_ERR;
+               break;
+       }
+       if (txt != NULL) {
+               snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
+               vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
+       } else {
+               vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+       }
+       if (log_on_stderr) {
+               fprintf(stderr, "%s\r\n", msgbuf);
+       } else {
+               openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
+               syslog(pri, "%.500s", msgbuf);
+               closelog();
+       }
+}
diff --git a/openssh/log.h b/openssh/log.h
new file mode 100644 (file)
index 0000000..23451f7
--- /dev/null
@@ -0,0 +1,66 @@
+/*     $OpenBSD: log.h,v 1.4 2001/06/26 17:27:24 markus Exp $  */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef SSH_LOG_H
+#define SSH_LOG_H
+
+#include <syslog.h> /* Needed for LOG_AUTHPRIV (if present) */
+
+/* Supported syslog facilities and levels. */
+typedef enum {
+       SYSLOG_FACILITY_DAEMON,
+       SYSLOG_FACILITY_USER,
+       SYSLOG_FACILITY_AUTH,
+#ifdef LOG_AUTHPRIV
+       SYSLOG_FACILITY_AUTHPRIV,
+#endif
+       SYSLOG_FACILITY_LOCAL0,
+       SYSLOG_FACILITY_LOCAL1,
+       SYSLOG_FACILITY_LOCAL2,
+       SYSLOG_FACILITY_LOCAL3,
+       SYSLOG_FACILITY_LOCAL4,
+       SYSLOG_FACILITY_LOCAL5,
+       SYSLOG_FACILITY_LOCAL6,
+       SYSLOG_FACILITY_LOCAL7
+}       SyslogFacility;
+
+typedef enum {
+       SYSLOG_LEVEL_QUIET,
+       SYSLOG_LEVEL_FATAL,
+       SYSLOG_LEVEL_ERROR,
+       SYSLOG_LEVEL_INFO,
+       SYSLOG_LEVEL_VERBOSE,
+       SYSLOG_LEVEL_DEBUG1,
+       SYSLOG_LEVEL_DEBUG2,
+       SYSLOG_LEVEL_DEBUG3
+}       LogLevel;
+
+void     log_init(char *, LogLevel, SyslogFacility, int);
+
+SyslogFacility log_facility_number(char *);
+LogLevel log_level_number(char *);
+
+void     fatal(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     error(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     log(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     verbose(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     debug(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     debug2(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     debug3(const char *, ...) __attribute__((format(printf, 1, 2)));
+
+void     fatal_cleanup(void);
+void     fatal_add_cleanup(void (*) (void *), void *);
+void     fatal_remove_cleanup(void (*) (void *), void *);
+
+#endif
diff --git a/openssh/loginrec.c b/openssh/loginrec.c
new file mode 100644 (file)
index 0000000..87c336d
--- /dev/null
@@ -0,0 +1,1507 @@
+/*
+ * Copyright (c) 2000 Andre Lucas.  All rights reserved.
+ * Portions copyright (c) 1998 Todd C. Miller
+ * Portions copyright (c) 1996 Jason Downs
+ * Portions copyright (c) 1996 Theo de Raadt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Markus Friedl.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ ** loginrec.c:  platform-independent login recording and lastlog retrieval
+ **/
+
+/*
+  The new login code explained
+  ============================
+
+  This code attempts to provide a common interface to login recording
+  (utmp and friends) and last login time retrieval.
+
+  Its primary means of achieving this is to use 'struct logininfo', a
+  union of all the useful fields in the various different types of
+  system login record structures one finds on UNIX variants.
+
+  We depend on autoconf to define which recording methods are to be
+  used, and which fields are contained in the relevant data structures
+  on the local system. Many C preprocessor symbols affect which code
+  gets compiled here.
+
+  The code is designed to make it easy to modify a particular
+  recording method, without affecting other methods nor requiring so
+  many nested conditional compilation blocks as were commonplace in
+  the old code.
+
+  For login recording, we try to use the local system's libraries as
+  these are clearly most likely to work correctly. For utmp systems
+  this usually means login() and logout() or setutent() etc., probably
+  in libutil, along with logwtmp() etc. On these systems, we fall back
+  to writing the files directly if we have to, though this method
+  requires very thorough testing so we do not corrupt local auditing
+  information. These files and their access methods are very system
+  specific indeed.
+
+  For utmpx systems, the corresponding library functions are
+  setutxent() etc. To the author's knowledge, all utmpx systems have
+  these library functions and so no direct write is attempted. If such
+  a system exists and needs support, direct analogues of the [uw]tmp
+  code should suffice.
+
+  Retrieving the time of last login ('lastlog') is in some ways even
+  more problemmatic than login recording. Some systems provide a
+  simple table of all users which we seek based on uid and retrieve a
+  relatively standard structure. Others record the same information in
+  a directory with a separate file, and others don't record the
+  information separately at all. For systems in the latter category,
+  we look backwards in the wtmp or wtmpx file for the last login entry
+  for our user. Naturally this is slower and on busy systems could
+  incur a significant performance penalty.
+
+  Calling the new code
+  --------------------
+
+  In OpenSSH all login recording and retrieval is performed in
+  login.c. Here you'll find working examples. Also, in the logintest.c
+  program there are more examples.
+
+  Internal handler calling method
+  -------------------------------
+
+  When a call is made to login_login() or login_logout(), both
+  routines set a struct logininfo flag defining which action (log in,
+  or log out) is to be taken. They both then call login_write(), which
+  calls whichever of the many structure-specific handlers autoconf
+  selects for the local system.
+
+  The handlers themselves handle system data structure specifics. Both
+  struct utmp and struct utmpx have utility functions (see
+  construct_utmp*()) to try to make it simpler to add extra systems
+  that introduce new features to either structure.
+
+  While it may seem terribly wasteful to replicate so much similar
+  code for each method, experience has shown that maintaining code to
+  write both struct utmp and utmpx in one function, whilst maintaining
+  support for all systems whether they have library support or not, is
+  a difficult and time-consuming task.
+
+  Lastlog support proceeds similarly. Functions login_get_lastlog()
+  (and its OpenSSH-tuned friend login_get_lastlog_time()) call
+  getlast_entry(), which tries one of three methods to find the last
+  login time. It uses local system lastlog support if it can,
+  otherwise it tries wtmp or wtmpx before giving up and returning 0,
+  meaning "tilt".
+
+  Maintenance
+  -----------
+
+  In many cases it's possible to tweak autoconf to select the correct
+  methods for a particular platform, either by improving the detection
+  code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
+  symbols for the platform.
+
+  Use logintest to check which symbols are defined before modifying
+  configure.ac and loginrec.c. (You have to build logintest yourself
+  with 'make logintest' as it's not built by default.)
+
+  Otherwise, patches to the specific method(s) are very helpful!
+
+*/
+
+/**
+ ** TODO:
+ **   homegrown ttyslot()
+ **   test, test, test
+ **
+ ** Platform status:
+ ** ----------------
+ **
+ ** Known good:
+ **   Linux (Redhat 6.2, Debian)
+ **   Solaris
+ **   HP-UX 10.20 (gcc only)
+ **   IRIX
+ **   NeXT - M68k/HPPA/Sparc (4.2/3.3)
+ **
+ ** Testing required: Please send reports!
+ **   NetBSD
+ **   HP-UX 11
+ **   AIX
+ **
+ ** Platforms with known problems:
+ **   Some variants of Slackware Linux
+ **
+ **/
+
+#include "includes.h"
+
+#include "ssh.h"
+#include "xmalloc.h"
+#include "loginrec.h"
+#include "log.h"
+#include "atomicio.h"
+
+RCSID("$Id$");
+
+#ifdef HAVE_UTIL_H
+#  include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+#   include <libutil.h>
+#endif
+
+/**
+ ** prototypes for helper functions in this file
+ **/
+
+#if HAVE_UTMP_H
+void set_utmp_time(struct logininfo *li, struct utmp *ut);
+void construct_utmp(struct logininfo *li, struct utmp *ut);
+#endif
+
+#ifdef HAVE_UTMPX_H
+void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
+void construct_utmpx(struct logininfo *li, struct utmpx *ut);
+#endif
+
+int utmp_write_entry(struct logininfo *li);
+int utmpx_write_entry(struct logininfo *li);
+int wtmp_write_entry(struct logininfo *li);
+int wtmpx_write_entry(struct logininfo *li);
+int lastlog_write_entry(struct logininfo *li);
+int syslogin_write_entry(struct logininfo *li);
+
+int getlast_entry(struct logininfo *li);
+int lastlog_get_entry(struct logininfo *li);
+int wtmp_get_entry(struct logininfo *li);
+int wtmpx_get_entry(struct logininfo *li);
+
+/* pick the shortest string */
+#define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
+
+/**
+ ** platform-independent login functions
+ **/
+
+/* login_login(struct logininfo *)     -Record a login
+ *
+ * Call with a pointer to a struct logininfo initialised with
+ * login_init_entry() or login_alloc_entry()
+ *
+ * Returns:
+ *  >0 if successful
+ *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
+ */
+int
+login_login (struct logininfo *li)
+{
+       li->type = LTYPE_LOGIN;
+       return login_write(li);
+}
+
+
+/* login_logout(struct logininfo *)     - Record a logout
+ *
+ * Call as with login_login()
+ *
+ * Returns:
+ *  >0 if successful
+ *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
+ */
+int
+login_logout(struct logininfo *li)
+{
+       li->type = LTYPE_LOGOUT;
+       return login_write(li);
+}
+
+/* login_get_lastlog_time(int)           - Retrieve the last login time
+ *
+ * Retrieve the last login time for the given uid. Will try to use the
+ * system lastlog facilities if they are available, but will fall back
+ * to looking in wtmp/wtmpx if necessary
+ *
+ * Returns:
+ *   0 on failure, or if user has never logged in
+ *   Time in seconds from the epoch if successful
+ *
+ * Useful preprocessor symbols:
+ *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
+ *                    info
+ *   USE_LASTLOG: If set, indicates the presence of system lastlog
+ *                facilities. If this and DISABLE_LASTLOG are not set,
+ *                try to retrieve lastlog information from wtmp/wtmpx.
+ */
+unsigned int
+login_get_lastlog_time(const int uid)
+{
+       struct logininfo li;
+
+       if (login_get_lastlog(&li, uid))
+               return li.tv_sec;
+       else
+               return 0;
+}
+
+/* login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
+ *
+ * Retrieve a logininfo structure populated (only partially) with
+ * information from the system lastlog data, or from wtmp/wtmpx if no
+ * system lastlog information exists.
+ *
+ * Note this routine must be given a pre-allocated logininfo.
+ *
+ * Returns:
+ *  >0: A pointer to your struct logininfo if successful
+ *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
+ *
+ */
+struct logininfo *
+login_get_lastlog(struct logininfo *li, const int uid)
+{
+       struct passwd *pw;
+
+       memset(li, '\0', sizeof(*li));
+       li->uid = uid;
+
+       /*
+        * If we don't have a 'real' lastlog, we need the username to
+        * reliably search wtmp(x) for the last login (see
+        * wtmp_get_entry().)
+        */
+       pw = getpwuid(uid);
+       if (pw == NULL)
+               fatal("login_get_lastlog: Cannot find account for uid %i", uid);
+
+       /* No MIN_SIZEOF here - we absolutely *must not* truncate the
+        * username */
+       strlcpy(li->username, pw->pw_name, sizeof(li->username));
+
+       if (getlast_entry(li))
+               return li;
+       else
+               return NULL;
+}
+
+
+/* login_alloc_entry(int, char*, char*, char*)    - Allocate and initialise
+ *                                                  a logininfo structure
+ *
+ * This function creates a new struct logininfo, a data structure
+ * meant to carry the information required to portably record login info.
+ *
+ * Returns a pointer to a newly created struct logininfo. If memory
+ * allocation fails, the program halts.
+ */
+struct
+logininfo *login_alloc_entry(int pid, const char *username,
+                            const char *hostname, const char *line)
+{
+       struct logininfo *newli;
+
+       newli = (struct logininfo *) xmalloc (sizeof(*newli));
+       (void)login_init_entry(newli, pid, username, hostname, line);
+       return newli;
+}
+
+
+/* login_free_entry(struct logininfo *)    - free struct memory */
+void
+login_free_entry(struct logininfo *li)
+{
+       xfree(li);
+}
+
+
+/* login_init_entry(struct logininfo *, int, char*, char*, char*)
+ *                                        - initialise a struct logininfo
+ *
+ * Populates a new struct logininfo, a data structure meant to carry
+ * the information required to portably record login info.
+ *
+ * Returns: 1
+ */
+int
+login_init_entry(struct logininfo *li, int pid, const char *username,
+                const char *hostname, const char *line)
+{
+       struct passwd *pw;
+
+       memset(li, 0, sizeof(*li));
+
+       li->pid = pid;
+
+       /* set the line information */
+       if (line)
+               line_fullname(li->line, line, sizeof(li->line));
+
+       if (username) {
+               strlcpy(li->username, username, sizeof(li->username));
+               pw = getpwnam(li->username);
+               if (pw == NULL)
+                       fatal("login_init_entry: Cannot find user \"%s\"", li->username);
+               li->uid = pw->pw_uid;
+       }
+
+       if (hostname)
+               strlcpy(li->hostname, hostname, sizeof(li->hostname));
+
+       return 1;
+}
+
+/* login_set_current_time(struct logininfo *)    - set the current time
+ *
+ * Set the current time in a logininfo structure. This function is
+ * meant to eliminate the need to deal with system dependencies for
+ * time handling.
+ */
+void
+login_set_current_time(struct logininfo *li)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       li->tv_sec = tv.tv_sec;
+       li->tv_usec = tv.tv_usec;
+}
+
+/* copy a sockaddr_* into our logininfo */
+void
+login_set_addr(struct logininfo *li, const struct sockaddr *sa,
+              const unsigned int sa_size)
+{
+       unsigned int bufsize = sa_size;
+
+       /* make sure we don't overrun our union */
+       if (sizeof(li->hostaddr) < sa_size)
+               bufsize = sizeof(li->hostaddr);
+
+       memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
+}
+
+
+/**
+ ** login_write: Call low-level recording functions based on autoconf
+ ** results
+ **/
+int
+login_write (struct logininfo *li)
+{
+#ifndef HAVE_CYGWIN
+       if ((int)geteuid() != 0) {
+         log("Attempt to write login records by non-root user (aborting)");
+         return 1;
+       }
+#endif
+
+       /* set the timestamp */
+       login_set_current_time(li);
+#ifdef USE_LOGIN
+       syslogin_write_entry(li);
+#endif
+#ifdef USE_LASTLOG
+       if (li->type == LTYPE_LOGIN) {
+               lastlog_write_entry(li);
+       }
+#endif
+#ifdef USE_UTMP
+       utmp_write_entry(li);
+#endif
+#ifdef USE_WTMP
+       wtmp_write_entry(li);
+#endif
+#ifdef USE_UTMPX
+       utmpx_write_entry(li);
+#endif
+#ifdef USE_WTMPX
+       wtmpx_write_entry(li);
+#endif
+       return 0;
+}
+
+#ifdef LOGIN_NEEDS_UTMPX
+int
+login_utmp_only(struct logininfo *li)
+{
+       li->type = LTYPE_LOGIN; 
+       login_set_current_time(li);
+# ifdef USE_UTMP
+       utmp_write_entry(li);
+# endif
+# ifdef USE_WTMP
+       wtmp_write_entry(li);
+# endif
+# ifdef USE_UTMPX
+       utmpx_write_entry(li);
+# endif
+# ifdef USE_WTMPX
+       wtmpx_write_entry(li);
+# endif
+       return 0;
+}
+#endif
+
+/**
+ ** getlast_entry: Call low-level functions to retrieve the last login
+ **                time.
+ **/
+
+/* take the uid in li and return the last login time */
+int
+getlast_entry(struct logininfo *li)
+{
+#ifdef USE_LASTLOG
+       return(lastlog_get_entry(li));
+#else /* !USE_LASTLOG */
+
+#ifdef DISABLE_LASTLOG
+       /* On some systems we shouldn't even try to obtain last login
+        * time, e.g. AIX */
+       return 0;
+# else /* DISABLE_LASTLOG */
+       /* Try to retrieve the last login time from wtmp */
+#  if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
+       /* retrieve last login time from utmp */
+       return (wtmp_get_entry(li));
+#  else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
+       /* If wtmp isn't available, try wtmpx */
+#   if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
+       /* retrieve last login time from utmpx */
+       return (wtmpx_get_entry(li));
+#   else
+       /* Give up: No means of retrieving last login time */
+       return 0;
+#   endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
+#  endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
+# endif /* DISABLE_LASTLOG */
+#endif /* USE_LASTLOG */
+}
+
+
+
+/*
+ * 'line' string utility functions
+ *
+ * These functions process the 'line' string into one of three forms:
+ *
+ * 1. The full filename (including '/dev')
+ * 2. The stripped name (excluding '/dev')
+ * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
+ *                               /dev/pts/1  -> ts/1 )
+ *
+ * Form 3 is used on some systems to identify a .tmp.? entry when
+ * attempting to remove it. Typically both addition and removal is
+ * performed by one application - say, sshd - so as long as the choice
+ * uniquely identifies a terminal it's ok.
+ */
+
+
+/* line_fullname(): add the leading '/dev/' if it doesn't exist make
+ * sure dst has enough space, if not just copy src (ugh) */
+char *
+line_fullname(char *dst, const char *src, int dstsize)
+{
+       memset(dst, '\0', dstsize);
+       if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) {
+               strlcpy(dst, src, dstsize);
+       } else {
+               strlcpy(dst, "/dev/", dstsize);
+               strlcat(dst, src, dstsize);
+       }
+       return dst;
+}
+
+/* line_stripname(): strip the leading '/dev' if it exists, return dst */
+char *
+line_stripname(char *dst, const char *src, int dstsize)
+{
+       memset(dst, '\0', dstsize);
+       if (strncmp(src, "/dev/", 5) == 0)
+               strlcpy(dst, src + 5, dstsize);
+       else
+               strlcpy(dst, src, dstsize);
+       return dst;
+}
+
+/* line_abbrevname(): Return the abbreviated (usually four-character)
+ * form of the line (Just use the last <dstsize> characters of the
+ * full name.)
+ *
+ * NOTE: use strncpy because we do NOT necessarily want zero
+ * termination */
+char *
+line_abbrevname(char *dst, const char *src, int dstsize)
+{
+       size_t len;
+
+       memset(dst, '\0', dstsize);
+
+       /* Always skip prefix if present */
+       if (strncmp(src, "/dev/", 5) == 0)
+               src += 5;
+
+       len = strlen(src);
+
+       if (len > 0) {
+               if (((int)len - dstsize) > 0)
+                       src +=  ((int)len - dstsize);
+
+               /* note: _don't_ change this to strlcpy */
+               strncpy(dst, src, (size_t)dstsize);
+       }
+
+       return dst;
+}
+
+/**
+ ** utmp utility functions
+ **
+ ** These functions manipulate struct utmp, taking system differences
+ ** into account.
+ **/
+
+#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
+
+/* build the utmp structure */
+void
+set_utmp_time(struct logininfo *li, struct utmp *ut)
+{
+# ifdef HAVE_TV_IN_UTMP
+       ut->ut_tv.tv_sec = li->tv_sec;
+       ut->ut_tv.tv_usec = li->tv_usec;
+# else
+#  ifdef HAVE_TIME_IN_UTMP
+       ut->ut_time = li->tv_sec;
+#  endif
+# endif
+}
+
+void
+construct_utmp(struct logininfo *li,
+                   struct utmp *ut)
+{
+       memset(ut, '\0', sizeof(*ut));
+
+       /* First fill out fields used for both logins and logouts */
+
+# ifdef HAVE_ID_IN_UTMP
+       line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
+# endif
+
+# ifdef HAVE_TYPE_IN_UTMP
+       /* This is done here to keep utmp constants out of struct logininfo */
+       switch (li->type) {
+       case LTYPE_LOGIN:
+               ut->ut_type = USER_PROCESS;
+#ifdef _CRAY
+               cray_set_tmpdir(ut);
+#endif
+               break;
+       case LTYPE_LOGOUT:
+               ut->ut_type = DEAD_PROCESS;
+#ifdef _CRAY
+               cray_retain_utmp(ut, li->pid);
+#endif
+               break;
+       }
+# endif
+       set_utmp_time(li, ut);
+
+       line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
+
+# ifdef HAVE_PID_IN_UTMP
+       ut->ut_pid = li->pid;
+# endif
+
+       /* If we're logging out, leave all other fields blank */
+       if (li->type == LTYPE_LOGOUT)
+         return;
+
+       /*
+        * These fields are only used when logging in, and are blank
+        * for logouts.
+        */
+
+       /* Use strncpy because we don't necessarily want null termination */
+       strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
+# ifdef HAVE_HOST_IN_UTMP
+       strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
+# endif
+# ifdef HAVE_ADDR_IN_UTMP
+       /* this is just a 32-bit IP address */
+       if (li->hostaddr.sa.sa_family == AF_INET)
+               ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
+# endif
+}
+#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
+
+/**
+ ** utmpx utility functions
+ **
+ ** These functions manipulate struct utmpx, accounting for system
+ ** variations.
+ **/
+
+#if defined(USE_UTMPX) || defined (USE_WTMPX)
+/* build the utmpx structure */
+void
+set_utmpx_time(struct logininfo *li, struct utmpx *utx)
+{
+# ifdef HAVE_TV_IN_UTMPX
+       utx->ut_tv.tv_sec = li->tv_sec;
+       utx->ut_tv.tv_usec = li->tv_usec;
+# else /* HAVE_TV_IN_UTMPX */
+#  ifdef HAVE_TIME_IN_UTMPX
+       utx->ut_time = li->tv_sec;
+#  endif /* HAVE_TIME_IN_UTMPX */
+# endif /* HAVE_TV_IN_UTMPX */
+}
+
+void
+construct_utmpx(struct logininfo *li, struct utmpx *utx)
+{
+       memset(utx, '\0', sizeof(*utx));
+# ifdef HAVE_ID_IN_UTMPX
+       line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
+# endif
+
+       /* this is done here to keep utmp constants out of loginrec.h */
+       switch (li->type) {
+       case LTYPE_LOGIN:
+               utx->ut_type = USER_PROCESS;
+               break;
+       case LTYPE_LOGOUT:
+               utx->ut_type = DEAD_PROCESS;
+               break;
+       }
+       line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
+       set_utmpx_time(li, utx);
+       utx->ut_pid = li->pid;
+
+       if (li->type == LTYPE_LOGOUT)
+               return;
+
+       /*
+        * These fields are only used when logging in, and are blank
+        * for logouts.
+        */
+
+       /* strncpy(): Don't necessarily want null termination */
+       strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
+# ifdef HAVE_HOST_IN_UTMPX
+       strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
+# endif
+# ifdef HAVE_ADDR_IN_UTMPX
+       /* this is just a 32-bit IP address */
+       if (li->hostaddr.sa.sa_family == AF_INET)
+               utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
+# endif
+# ifdef HAVE_SYSLEN_IN_UTMPX
+       /* ut_syslen is the length of the utx_host string */
+       utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
+# endif
+}
+#endif /* USE_UTMPX || USE_WTMPX */
+
+/**
+ ** Low-level utmp functions
+ **/
+
+/* FIXME: (ATL) utmp_write_direct needs testing */
+#ifdef USE_UTMP
+
+/* if we can, use pututline() etc. */
+# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
+       defined(HAVE_PUTUTLINE)
+#  define UTMP_USE_LIBRARY
+# endif
+
+
+/* write a utmp entry with the system's help (pututline() and pals) */
+# ifdef UTMP_USE_LIBRARY
+static int
+utmp_write_library(struct logininfo *li, struct utmp *ut)
+{
+       setutent();
+       pututline(ut);
+
+#  ifdef HAVE_ENDUTENT
+       endutent();
+#  endif
+       return 1;
+}
+# else /* UTMP_USE_LIBRARY */
+
+/* write a utmp entry direct to the file */
+/* This is a slightly modification of code in OpenBSD's login.c */
+static int
+utmp_write_direct(struct logininfo *li, struct utmp *ut)
+{
+       struct utmp old_ut;
+       register int fd;
+       int tty;
+
+       /* FIXME: (ATL) ttyslot() needs local implementation */
+
+#if defined(HAVE_GETTTYENT)
+       register struct ttyent *ty;
+
+       tty=0;
+
+       setttyent();
+       while ((struct ttyent *)0 != (ty = getttyent())) {
+               tty++;
+               if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
+                       break;
+       }
+       endttyent();
+
+       if((struct ttyent *)0 == ty) {
+               log("utmp_write_entry: tty not found");
+               return(1);
+       }
+#else /* FIXME */
+
+       tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
+
+#endif /* HAVE_GETTTYENT */
+
+       if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
+               (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
+               /*
+                * Prevent luser from zero'ing out ut_host.
+                * If the new ut_line is empty but the old one is not
+                * and ut_line and ut_name match, preserve the old ut_line.
+                */
+               if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
+                       (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
+                       (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
+                       (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
+                       (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
+               }
+
+               (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
+               if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
+                       log("utmp_write_direct: error writing %s: %s",
+                           UTMP_FILE, strerror(errno));
+
+               (void)close(fd);
+               return 1;
+       } else {
+               return 0;
+       }
+}
+# endif /* UTMP_USE_LIBRARY */
+
+static int
+utmp_perform_login(struct logininfo *li)
+{
+       struct utmp ut;
+
+       construct_utmp(li, &ut);
+# ifdef UTMP_USE_LIBRARY
+       if (!utmp_write_library(li, &ut)) {
+               log("utmp_perform_login: utmp_write_library() failed");
+               return 0;
+       }
+# else
+       if (!utmp_write_direct(li, &ut)) {
+               log("utmp_perform_login: utmp_write_direct() failed");
+               return 0;
+       }
+# endif
+       return 1;
+}
+
+
+static int
+utmp_perform_logout(struct logininfo *li)
+{
+       struct utmp ut;
+
+       construct_utmp(li, &ut);
+# ifdef UTMP_USE_LIBRARY
+       if (!utmp_write_library(li, &ut)) {
+               log("utmp_perform_logout: utmp_write_library() failed");
+               return 0;
+       }
+# else
+       if (!utmp_write_direct(li, &ut)) {
+               log("utmp_perform_logout: utmp_write_direct() failed");
+               return 0;
+       }
+# endif
+       return 1;
+}
+
+
+int
+utmp_write_entry(struct logininfo *li)
+{
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               return utmp_perform_login(li);
+
+       case LTYPE_LOGOUT:
+               return utmp_perform_logout(li);
+
+       default:
+               log("utmp_write_entry: invalid type field");
+               return 0;
+       }
+}
+#endif /* USE_UTMP */
+
+
+/**
+ ** Low-level utmpx functions
+ **/
+
+/* not much point if we don't want utmpx entries */
+#ifdef USE_UTMPX
+
+/* if we have the wherewithall, use pututxline etc. */
+# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
+       defined(HAVE_PUTUTXLINE)
+#  define UTMPX_USE_LIBRARY
+# endif
+
+
+/* write a utmpx entry with the system's help (pututxline() and pals) */
+# ifdef UTMPX_USE_LIBRARY
+static int
+utmpx_write_library(struct logininfo *li, struct utmpx *utx)
+{
+       setutxent();
+       pututxline(utx);
+
+#  ifdef HAVE_ENDUTXENT
+       endutxent();
+#  endif
+       return 1;
+}
+
+# else /* UTMPX_USE_LIBRARY */
+
+/* write a utmp entry direct to the file */
+static int
+utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
+{
+       log("utmpx_write_direct: not implemented!");
+       return 0;
+}
+# endif /* UTMPX_USE_LIBRARY */
+
+static int
+utmpx_perform_login(struct logininfo *li)
+{
+       struct utmpx utx;
+
+       construct_utmpx(li, &utx);
+# ifdef UTMPX_USE_LIBRARY
+       if (!utmpx_write_library(li, &utx)) {
+               log("utmpx_perform_login: utmp_write_library() failed");
+               return 0;
+       }
+# else
+       if (!utmpx_write_direct(li, &ut)) {
+               log("utmpx_perform_login: utmp_write_direct() failed");
+               return 0;
+       }
+# endif
+       return 1;
+}
+
+
+static int
+utmpx_perform_logout(struct logininfo *li)
+{
+       struct utmpx utx;
+
+       memset(&utx, '\0', sizeof(utx));
+       set_utmpx_time(li, &utx);
+       line_stripname(utx.ut_line, li->line, sizeof(utx.ut_line));
+# ifdef HAVE_ID_IN_UTMPX
+       line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
+# endif
+# ifdef HAVE_TYPE_IN_UTMPX
+       utx.ut_type = DEAD_PROCESS;
+# endif
+
+# ifdef UTMPX_USE_LIBRARY
+       utmpx_write_library(li, &utx);
+# else
+       utmpx_write_direct(li, &utx);
+# endif
+       return 1;
+}
+
+int
+utmpx_write_entry(struct logininfo *li)
+{
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               return utmpx_perform_login(li);
+       case LTYPE_LOGOUT:
+               return utmpx_perform_logout(li);
+       default:
+               log("utmpx_write_entry: invalid type field");
+               return 0;
+       }
+}
+#endif /* USE_UTMPX */
+
+
+/**
+ ** Low-level wtmp functions
+ **/
+
+#ifdef USE_WTMP
+
+/* write a wtmp entry direct to the end of the file */
+/* This is a slight modification of code in OpenBSD's logwtmp.c */
+static int
+wtmp_write(struct logininfo *li, struct utmp *ut)
+{
+       struct stat buf;
+       int fd, ret = 1;
+
+       if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
+               log("wtmp_write: problem writing %s: %s",
+                   WTMP_FILE, strerror(errno));
+               return 0;
+       }
+       if (fstat(fd, &buf) == 0)
+               if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
+                       ftruncate(fd, buf.st_size);
+                       log("wtmp_write: problem writing %s: %s",
+                           WTMP_FILE, strerror(errno));
+                       ret = 0;
+               }
+       (void)close(fd);
+       return ret;
+}
+
+static int
+wtmp_perform_login(struct logininfo *li)
+{
+       struct utmp ut;
+
+       construct_utmp(li, &ut);
+       return wtmp_write(li, &ut);
+}
+
+
+static int
+wtmp_perform_logout(struct logininfo *li)
+{
+       struct utmp ut;
+
+       construct_utmp(li, &ut);
+       return wtmp_write(li, &ut);
+}
+
+
+int
+wtmp_write_entry(struct logininfo *li)
+{
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               return wtmp_perform_login(li);
+       case LTYPE_LOGOUT:
+               return wtmp_perform_logout(li);
+       default:
+               log("wtmp_write_entry: invalid type field");
+               return 0;
+       }
+}
+
+
+/* Notes on fetching login data from wtmp/wtmpx
+ *
+ * Logouts are usually recorded with (amongst other things) a blank
+ * username on a given tty line.  However, some systems (HP-UX is one)
+ * leave all fields set, but change the ut_type field to DEAD_PROCESS.
+ *
+ * Since we're only looking for logins here, we know that the username
+ * must be set correctly. On systems that leave it in, we check for
+ * ut_type==USER_PROCESS (indicating a login.)
+ *
+ * Portability: Some systems may set something other than USER_PROCESS
+ * to indicate a login process. I don't know of any as I write. Also,
+ * it's possible that some systems may both leave the username in
+ * place and not have ut_type.
+ */
+
+/* return true if this wtmp entry indicates a login */
+static int
+wtmp_islogin(struct logininfo *li, struct utmp *ut)
+{
+       if (strncmp(li->username, ut->ut_name,
+               MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
+# ifdef HAVE_TYPE_IN_UTMP
+               if (ut->ut_type & USER_PROCESS)
+                       return 1;
+# else
+               return 1;
+# endif
+       }
+       return 0;
+}
+
+int
+wtmp_get_entry(struct logininfo *li)
+{
+       struct stat st;
+       struct utmp ut;
+       int fd, found=0;
+
+       /* Clear the time entries in our logininfo */
+       li->tv_sec = li->tv_usec = 0;
+
+       if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
+               log("wtmp_get_entry: problem opening %s: %s",
+                   WTMP_FILE, strerror(errno));
+               return 0;
+       }
+       if (fstat(fd, &st) != 0) {
+               log("wtmp_get_entry: couldn't stat %s: %s",
+                   WTMP_FILE, strerror(errno));
+               close(fd);
+               return 0;
+       }
+
+       /* Seek to the start of the last struct utmp */
+       if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
+               /* Looks like we've got a fresh wtmp file */
+               close(fd);
+               return 0;
+       }
+
+       while (!found) {
+               if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
+                       log("wtmp_get_entry: read of %s failed: %s",
+                           WTMP_FILE, strerror(errno));
+                       close (fd);
+                       return 0;
+               }
+               if ( wtmp_islogin(li, &ut) ) {
+                       found = 1;
+                       /* We've already checked for a time in struct
+                        * utmp, in login_getlast(). */
+# ifdef HAVE_TIME_IN_UTMP
+                       li->tv_sec = ut.ut_time;
+# else
+#  if HAVE_TV_IN_UTMP
+                       li->tv_sec = ut.ut_tv.tv_sec;
+#  endif
+# endif
+                       line_fullname(li->line, ut.ut_line,
+                                     MIN_SIZEOF(li->line, ut.ut_line));
+# ifdef HAVE_HOST_IN_UTMP
+                       strlcpy(li->hostname, ut.ut_host,
+                               MIN_SIZEOF(li->hostname, ut.ut_host));
+# endif
+                       continue;
+               }
+               /* Seek back 2 x struct utmp */
+               if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
+                       /* We've found the start of the file, so quit */
+                       close (fd);
+                       return 0;
+               }
+       }
+
+       /* We found an entry. Tidy up and return */
+       close(fd);
+       return 1;
+}
+# endif /* USE_WTMP */
+
+
+/**
+ ** Low-level wtmpx functions
+ **/
+
+#ifdef USE_WTMPX
+/* write a wtmpx entry direct to the end of the file */
+/* This is a slight modification of code in OpenBSD's logwtmp.c */
+static int
+wtmpx_write(struct logininfo *li, struct utmpx *utx)
+{
+       struct stat buf;
+       int fd, ret = 1;
+
+       if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
+               log("wtmpx_write: problem opening %s: %s",
+                   WTMPX_FILE, strerror(errno));
+               return 0;
+       }
+
+       if (fstat(fd, &buf) == 0)
+               if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
+                       ftruncate(fd, buf.st_size);
+                       log("wtmpx_write: problem writing %s: %s",
+                           WTMPX_FILE, strerror(errno));
+                       ret = 0;
+               }
+       (void)close(fd);
+
+       return ret;
+}
+
+
+static int
+wtmpx_perform_login(struct logininfo *li)
+{
+       struct utmpx utx;
+
+       construct_utmpx(li, &utx);
+       return wtmpx_write(li, &utx);
+}
+
+
+static int
+wtmpx_perform_logout(struct logininfo *li)
+{
+       struct utmpx utx;
+
+       construct_utmpx(li, &utx);
+       return wtmpx_write(li, &utx);
+}
+
+
+int
+wtmpx_write_entry(struct logininfo *li)
+{
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               return wtmpx_perform_login(li);
+       case LTYPE_LOGOUT:
+               return wtmpx_perform_logout(li);
+       default:
+               log("wtmpx_write_entry: invalid type field");
+               return 0;
+       }
+}
+
+/* Please see the notes above wtmp_islogin() for information about the
+   next two functions */
+
+/* Return true if this wtmpx entry indicates a login */
+static int
+wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
+{
+       if ( strncmp(li->username, utx->ut_name,
+               MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
+# ifdef HAVE_TYPE_IN_UTMPX
+               if (utx->ut_type == USER_PROCESS)
+                       return 1;
+# else
+               return 1;
+# endif
+       }
+       return 0;
+}
+
+
+int
+wtmpx_get_entry(struct logininfo *li)
+{
+       struct stat st;
+       struct utmpx utx;
+       int fd, found=0;
+
+       /* Clear the time entries */
+       li->tv_sec = li->tv_usec = 0;
+
+       if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
+               log("wtmpx_get_entry: problem opening %s: %s",
+                   WTMPX_FILE, strerror(errno));
+               return 0;
+       }
+       if (fstat(fd, &st) != 0) {
+               log("wtmpx_get_entry: couldn't stat %s: %s",
+                   WTMP_FILE, strerror(errno));
+               close(fd);
+               return 0;
+       }
+
+       /* Seek to the start of the last struct utmpx */
+       if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
+               /* probably a newly rotated wtmpx file */
+               close(fd);
+               return 0;
+       }
+
+       while (!found) {
+               if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
+                       log("wtmpx_get_entry: read of %s failed: %s",
+                           WTMPX_FILE, strerror(errno));
+                       close (fd);
+                       return 0;
+               }
+               /* Logouts are recorded as a blank username on a particular line.
+                * So, we just need to find the username in struct utmpx */
+               if ( wtmpx_islogin(li, &utx) ) {
+# ifdef HAVE_TV_IN_UTMPX
+                       li->tv_sec = utx.ut_tv.tv_sec;
+# else
+#  ifdef HAVE_TIME_IN_UTMPX
+                       li->tv_sec = utx.ut_time;
+#  endif
+# endif
+                       line_fullname(li->line, utx.ut_line, sizeof(li->line));
+# ifdef HAVE_HOST_IN_UTMPX
+                       strlcpy(li->hostname, utx.ut_host,
+                               MIN_SIZEOF(li->hostname, utx.ut_host));
+# endif
+                       continue;
+               }
+               if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
+                       close (fd);
+                       return 0;
+               }
+       }
+
+       close(fd);
+       return 1;
+}
+#endif /* USE_WTMPX */
+
+/**
+ ** Low-level libutil login() functions
+ **/
+
+#ifdef USE_LOGIN
+static int
+syslogin_perform_login(struct logininfo *li)
+{
+       struct utmp *ut;
+
+       if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
+               log("syslogin_perform_login: couldn't malloc()");
+               return 0;
+       }
+       construct_utmp(li, ut);
+       login(ut);
+
+       return 1;
+}
+
+static int
+syslogin_perform_logout(struct logininfo *li)
+{
+# ifdef HAVE_LOGOUT
+       char line[8];
+
+       (void)line_stripname(line, li->line, sizeof(line));
+
+       if (!logout(line)) {
+               log("syslogin_perform_logout: logout() returned an error");
+#  ifdef HAVE_LOGWTMP
+       } else {
+               logwtmp(line, "", "");
+#  endif
+       }
+       /* FIXME: (ATL - if the need arises) What to do if we have
+        * login, but no logout?  what if logout but no logwtmp? All
+        * routines are in libutil so they should all be there,
+        * but... */
+# endif
+       return 1;
+}
+
+int
+syslogin_write_entry(struct logininfo *li)
+{
+       switch (li->type) {
+       case LTYPE_LOGIN:
+               return syslogin_perform_login(li);
+       case LTYPE_LOGOUT:
+               return syslogin_perform_logout(li);
+       default:
+               log("syslogin_write_entry: Invalid type field");
+               return 0;
+       }
+}
+#endif /* USE_LOGIN */
+
+/* end of file log-syslogin.c */
+
+/**
+ ** Low-level lastlog functions
+ **/
+
+#ifdef USE_LASTLOG
+#define LL_FILE 1
+#define LL_DIR 2
+#define LL_OTHER 3
+
+static void
+lastlog_construct(struct logininfo *li, struct lastlog *last)
+{
+       /* clear the structure */
+       memset(last, '\0', sizeof(*last));
+
+       (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
+       strlcpy(last->ll_host, li->hostname,
+               MIN_SIZEOF(last->ll_host, li->hostname));
+       last->ll_time = li->tv_sec;
+}
+
+static int
+lastlog_filetype(char *filename)
+{
+       struct stat st;
+
+       if (stat(LASTLOG_FILE, &st) != 0) {
+               log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
+                       strerror(errno));
+               return 0;
+       }
+       if (S_ISDIR(st.st_mode))
+               return LL_DIR;
+       else if (S_ISREG(st.st_mode))
+               return LL_FILE;
+       else
+               return LL_OTHER;
+}
+
+
+/* open the file (using filemode) and seek to the login entry */
+static int
+lastlog_openseek(struct logininfo *li, int *fd, int filemode)
+{
+       off_t offset;
+       int type;
+       char lastlog_file[1024];
+
+       type = lastlog_filetype(LASTLOG_FILE);
+       switch (type) {
+               case LL_FILE:
+                       strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
+                       break;
+               case LL_DIR:
+                       snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
+                                LASTLOG_FILE, li->username);
+                       break;
+               default:
+                       log("lastlog_openseek: %.100s is not a file or directory!",
+                           LASTLOG_FILE);
+                       return 0;
+       }
+
+       *fd = open(lastlog_file, filemode);
+       if ( *fd < 0) {
+               debug("lastlog_openseek: Couldn't open %s: %s",
+                   lastlog_file, strerror(errno));
+               return 0;
+       }
+
+       if (type == LL_FILE) {
+               /* find this uid's offset in the lastlog file */
+               offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
+
+               if ( lseek(*fd, offset, SEEK_SET) != offset ) {
+                       log("lastlog_openseek: %s->lseek(): %s",
+                        lastlog_file, strerror(errno));
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static int
+lastlog_perform_login(struct logininfo *li)
+{
+       struct lastlog last;
+       int fd;
+
+       /* create our struct lastlog */
+       lastlog_construct(li, &last);
+
+       if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
+               return(0);
+
+       /* write the entry */
+       if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
+               close(fd);
+               log("lastlog_write_filemode: Error writing to %s: %s",
+                   LASTLOG_FILE, strerror(errno));
+               return 0;
+       }
+
+       close(fd);
+       return 1;
+}
+
+int
+lastlog_write_entry(struct logininfo *li)
+{
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               return lastlog_perform_login(li);
+       default:
+               log("lastlog_write_entry: Invalid type field");
+               return 0;
+       }
+}
+
+static void
+lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
+{
+       line_fullname(li->line, last->ll_line, sizeof(li->line));
+       strlcpy(li->hostname, last->ll_host,
+               MIN_SIZEOF(li->hostname, last->ll_host));
+       li->tv_sec = last->ll_time;
+}
+
+int
+lastlog_get_entry(struct logininfo *li)
+{
+       struct lastlog last;
+       int fd;
+
+       if (!lastlog_openseek(li, &fd, O_RDONLY))
+               return 0;
+
+       if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) {
+               close(fd);
+               log("lastlog_get_entry: Error reading from %s: %s",
+                   LASTLOG_FILE, strerror(errno));
+               return 0;
+       }
+
+       close(fd);
+
+       lastlog_populate_entry(li, &last);
+
+       return 1;
+}
+#endif /* USE_LASTLOG */
diff --git a/openssh/loginrec.h b/openssh/loginrec.h
new file mode 100644 (file)
index 0000000..a741205
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef _HAVE_LOGINREC_H_
+#define _HAVE_LOGINREC_H_
+
+/*
+ * Copyright (c) 2000 Andre Lucas.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Markus Friedl.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ ** loginrec.h:  platform-independent login recording and lastlog retrieval
+ **/
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+/* RCSID("$Id$"); */
+
+/**
+ ** you should use the login_* calls to work around platform dependencies
+ **/
+
+/*
+ * login_netinfo structure
+ */
+
+union login_netinfo {
+       struct sockaddr sa;
+       struct sockaddr_in sa_in;
+       struct sockaddr_storage sa_storage;
+};
+
+/*
+ *   * logininfo structure  *
+ */
+/* types - different to utmp.h 'type' macros */
+/* (though set to the same value as linux, openbsd and others...) */
+#define LTYPE_LOGIN    7
+#define LTYPE_LOGOUT   8
+
+/* string lengths - set very long */
+#define LINFO_PROGSIZE 64
+#define LINFO_LINESIZE 64
+#define LINFO_NAMESIZE 64
+#define LINFO_HOSTSIZE 256
+
+struct logininfo {
+       char       progname[LINFO_PROGSIZE];     /* name of program (for PAM) */
+       int        progname_null;
+       short int  type;                         /* type of login (LTYPE_*) */
+       int        pid;                          /* PID of login process */
+       int        uid;                          /* UID of this user */
+       char       line[LINFO_LINESIZE];         /* tty/pty name */
+       char       username[LINFO_NAMESIZE];     /* login username */
+       char       hostname[LINFO_HOSTSIZE];     /* remote hostname */
+       /* 'exit_status' structure components */
+       int        exit;                        /* process exit status */
+       int        termination;                 /* process termination status */
+       /* struct timeval (sys/time.h) isn't always available, if it isn't we'll
+        * use time_t's value as tv_sec and set tv_usec to 0
+        */
+       unsigned int tv_sec;
+       unsigned int tv_usec;
+       union login_netinfo hostaddr;       /* caller's host address(es) */
+}; /* struct logininfo */
+
+/*
+ * login recording functions
+ */
+
+/** 'public' functions */
+
+/* construct a new login entry */
+struct logininfo *login_alloc_entry(int pid, const char *username,
+                                   const char *hostname, const char *line);
+/* free a structure */
+void login_free_entry(struct logininfo *li);
+/* fill out a pre-allocated structure with useful information */
+int login_init_entry(struct logininfo *li, int pid, const char *username,
+                    const char *hostname, const char *line);
+/* place the current time in a logininfo struct */
+void login_set_current_time(struct logininfo *li);
+
+/* record the entry */
+int login_login (struct logininfo *li);
+int login_logout(struct logininfo *li);
+#ifdef LOGIN_NEEDS_UTMPX
+int login_utmp_only(struct logininfo *li);
+#endif
+
+/** End of public functions */
+
+/* record the entry */
+int login_write (struct logininfo *li);
+int login_log_entry(struct logininfo *li);
+
+/* set the network address based on network address type */
+void login_set_addr(struct logininfo *li, const struct sockaddr *sa,
+                   const unsigned int sa_size);
+
+/*
+ * lastlog retrieval functions
+ */
+/* lastlog *entry* functions fill out a logininfo */
+struct logininfo *login_get_lastlog(struct logininfo *li, const int uid);
+/* lastlog *time* functions return time_t equivalent (uint) */
+unsigned int login_get_lastlog_time(const int uid);
+
+/* produce various forms of the line filename */
+char *line_fullname(char *dst, const char *src, int dstsize);
+char *line_stripname(char *dst, const char *src, int dstsize);
+char *line_abbrevname(char *dst, const char *src, int dstsize);
+
+#endif /* _HAVE_LOGINREC_H_ */
diff --git a/openssh/logintest.c b/openssh/logintest.c
new file mode 100644 (file)
index 0000000..aa3f5f4
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2000 Andre Lucas.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Markus Friedl.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ ** logintest.c:  simple test driver for platform-independent login recording
+ **               and lastlog retrieval
+ **/
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <netdb.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "loginrec.h"
+
+RCSID("$Id$");
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+#define PAUSE_BEFORE_LOGOUT 3
+
+int nologtest = 0;
+int compile_opts_only = 0;
+int be_verbose = 0;
+
+
+/* Dump a logininfo to stdout. Assumes a tab size of 8 chars. */
+void
+dump_logininfo(struct logininfo *li, char *descname)
+{
+       /* yes I know how nasty this is */
+       printf("struct logininfo %s = {\n\t"
+              "progname\t'%s'\n\ttype\t\t%d\n\t"
+              "pid\t\t%d\n\tuid\t\t%d\n\t"
+              "line\t\t'%s'\n\tusername\t'%s'\n\t"
+              "hostname\t'%s'\n\texit\t\t%d\n\ttermination\t%d\n\t"
+              "tv_sec\t%d\n\ttv_usec\t%d\n\t"
+              "struct login_netinfo hostaddr {\n\t\t"
+              "struct sockaddr sa {\n"
+              "\t\t\tfamily\t%d\n\t\t}\n"
+              "\t}\n"
+              "}\n",
+              descname, li->progname, li->type,
+              li->pid, li->uid, li->line,
+              li->username, li->hostname, li->exit,
+              li->termination, li->tv_sec, li->tv_usec,
+              li->hostaddr.sa.sa_family);
+}
+
+
+int
+testAPI()
+{
+       struct logininfo *li1;
+       struct passwd *pw;
+       struct hostent *he;
+       struct sockaddr_in sa_in4;
+       char cmdstring[256], stripline[8];
+       char username[32];
+#ifdef HAVE_TIME_H
+       time_t t0, t1, t2, logintime, logouttime;
+       char s_t0[64],s_t1[64],s_t2[64];
+       char s_logintime[64], s_logouttime[64]; /* ctime() strings */
+#endif
+
+       printf("**\n** Testing the API...\n**\n");
+
+       pw = getpwuid(getuid());
+       strlcpy(username, pw->pw_name, sizeof(username));
+
+       /* gethostname(hostname, sizeof(hostname)); */
+
+       printf("login_alloc_entry test (no host info):\n");
+
+       /* FIXME fake tty more effectively - this could upset some platforms */
+       li1 = login_alloc_entry((int)getpid(), username, NULL, ttyname(0));
+       strlcpy(li1->progname, "OpenSSH-logintest", sizeof(li1->progname));
+
+       if (be_verbose)
+               dump_logininfo(li1, "li1");
+
+       printf("Setting host address info for 'localhost' (may call out):\n");
+       if (! (he = gethostbyname("localhost"))) {
+               printf("Couldn't set hostname(lookup failed)\n");
+       } else {
+               /* NOTE: this is messy, but typically a program wouldn't have to set
+                *  any of this, a sockaddr_in* would be already prepared */
+               memcpy((void *)&(sa_in4.sin_addr), (void *)&(he->h_addr_list[0][0]),
+                      sizeof(struct in_addr));
+               login_set_addr(li1, (struct sockaddr *) &sa_in4, sizeof(sa_in4));
+               strlcpy(li1->hostname, "localhost", sizeof(li1->hostname));
+       }
+       if (be_verbose)
+               dump_logininfo(li1, "li1");
+
+       if ((int)geteuid() != 0) {
+               printf("NOT RUNNING LOGIN TESTS - you are not root!\n");
+               return 1;
+       }
+
+       if (nologtest)
+               return 1;
+
+       line_stripname(stripline, li1->line, sizeof(stripline));
+
+       printf("Performing an invalid login attempt (no type field)\n--\n");
+       login_write(li1);
+       printf("--\n(Should have written errors to stderr)\n");
+
+#ifdef HAVE_TIME_H
+       (void)time(&t0);
+       strlcpy(s_t0, ctime(&t0), sizeof(s_t0));
+       t1 = login_get_lastlog_time(getuid());
+       strlcpy(s_t1, ctime(&t1), sizeof(s_t1));
+       printf("Before logging in:\n\tcurrent time is %d - %s\t"
+              "lastlog time is %d - %s\n",
+              (int)t0, s_t0, (int)t1, s_t1);
+#endif
+
+       printf("Performing a login on line %s ", stripline);
+#ifdef HAVE_TIME_H
+       (void)time(&logintime);
+       strlcpy(s_logintime, ctime(&logintime), sizeof(s_logintime));
+       printf("at %d - %s", (int)logintime, s_logintime);
+#endif
+       printf("--\n");
+       login_login(li1);
+
+       snprintf(cmdstring, sizeof(cmdstring), "who | grep '%s '",
+                stripline);
+       system(cmdstring);
+
+       printf("--\nPausing for %d second(s)...\n", PAUSE_BEFORE_LOGOUT);
+       sleep(PAUSE_BEFORE_LOGOUT);
+
+       printf("Performing a logout ");
+#ifdef HAVE_TIME_H
+       (void)time(&logouttime);
+       strlcpy(s_logouttime, ctime(&logouttime), sizeof(s_logouttime));
+       printf("at %d - %s", (int)logouttime, s_logouttime);
+#endif
+       printf("\nThe root login shown above should be gone.\n"
+              "If the root login hasn't gone, but another user on the same\n"
+              "pty has, this is OK - we're hacking it here, and there\n"
+              "shouldn't be two users on one pty in reality...\n"
+              "-- ('who' output follows)\n");
+       login_logout(li1);
+
+       system(cmdstring);
+       printf("-- ('who' output ends)\n");
+
+#ifdef HAVE_TIME_H
+       t2 = login_get_lastlog_time(getuid());
+       strlcpy(s_t2, ctime(&t2), sizeof(s_t2));
+       printf("After logging in, lastlog time is %d - %s\n", (int)t2, s_t2);
+       if (t1 == t2)
+               printf("The lastlog times before and after logging in are the "
+                      "same.\nThis indicates that lastlog is ** NOT WORKING "
+                      "CORRECTLY **\n");
+       else if (t0 != t2)
+               /* We can be off by a second or so, even when recording works fine.
+                * I'm not 100% sure why, but it's true. */
+               printf("** The login time and the lastlog time differ.\n"
+                      "** This indicates that lastlog is either recording the "
+                      "wrong time,\n** or retrieving the wrong entry.\n"
+                      "If it's off by less than %d second(s) "
+                      "run the test again.\n", PAUSE_BEFORE_LOGOUT);
+       else
+               printf("lastlog agrees with the login time. This is a good thing.\n");
+
+#endif
+
+       printf("--\nThe output of 'last' shown next should have "
+              "an entry for root \n  on %s for the time shown above:\n--\n",
+              stripline);
+       snprintf(cmdstring, sizeof(cmdstring), "last | grep '%s ' | head -3",
+                stripline);
+       system(cmdstring);
+
+       printf("--\nEnd of login test.\n");
+
+       login_free_entry(li1);
+
+       return 1;
+} /* testAPI() */
+
+
+void
+testLineName(char *line)
+{
+       /* have to null-terminate - these functions are designed for
+        * structures with fixed-length char arrays, and don't null-term.*/
+       char full[17], strip[9], abbrev[5];
+
+       memset(full, '\0', sizeof(full));
+       memset(strip, '\0', sizeof(strip));
+       memset(abbrev, '\0', sizeof(abbrev));
+
+       line_fullname(full, line, sizeof(full)-1);
+       line_stripname(strip, full, sizeof(strip)-1);
+       line_abbrevname(abbrev, full, sizeof(abbrev)-1);
+       printf("%s: %s, %s, %s\n", line, full, strip, abbrev);
+
+} /* testLineName() */
+
+
+int
+testOutput()
+{
+       printf("**\n** Testing linename functions\n**\n");
+       testLineName("/dev/pts/1");
+       testLineName("pts/1");
+       testLineName("pts/999");
+       testLineName("/dev/ttyp00");
+       testLineName("ttyp00");
+
+       return 1;
+} /* testOutput() */
+
+
+/* show which options got compiled in */
+void
+showOptions(void)
+{
+       printf("**\n** Compile-time options\n**\n");
+
+       printf("login recording methods selected:\n");
+#ifdef USE_LOGIN
+       printf("\tUSE_LOGIN\n");
+#endif
+#ifdef USE_UTMP
+       printf("\tUSE_UTMP (UTMP_FILE=%s)\n", UTMP_FILE);
+#endif
+#ifdef USE_UTMPX
+       printf("\tUSE_UTMPX (UTMPX_FILE=%s)\n", UTMPX_FILE);
+#endif
+#ifdef USE_WTMP
+       printf("\tUSE_WTMP (WTMP_FILE=%s)\n", WTMP_FILE);
+#endif
+#ifdef USE_WTMPX
+       printf("\tUSE_WTMPX (WTMPX_FILE=%s)\n", WTMPX_FILE);
+#endif
+#ifdef USE_LASTLOG
+       printf("\tUSE_LASTLOG (LASTLOG_FILE=%s)\n", LASTLOG_FILE);
+#endif
+       printf("\n");
+
+} /* showOptions() */
+
+
+int
+main(int argc, char *argv[])
+{
+       printf("Platform-independent login recording test driver\n");
+
+       __progname = get_progname(argv[0]);
+       if (argc == 2) {
+               if (strncmp(argv[1], "-i", 3) == 0)
+                       compile_opts_only = 1;
+               else if (strncmp(argv[1], "-v", 3) == 0)
+                       be_verbose=1;
+       }
+
+       if (!compile_opts_only) {
+               if (be_verbose && !testOutput())
+                       return 1;
+
+               if (!testAPI())
+                       return 1;
+       }
+
+       showOptions();
+
+       return 0;
+} /* main() */
+
diff --git a/openssh/mac.c b/openssh/mac.c
new file mode 100644 (file)
index 0000000..e8b4267
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: mac.c,v 1.2 2001/04/05 10:42:51 markus Exp $");
+
+#include <openssl/hmac.h>
+
+#include "xmalloc.h"
+#include "getput.h"
+#include "log.h"
+#include "cipher.h"
+#include "kex.h"
+#include "mac.h"
+
+struct {
+       char            *name;
+       EVP_MD *        (*mdfunc)(void);
+       int             truncatebits;   /* truncate digest if != 0 */
+} macs[] = {
+       { "hmac-sha1",                  EVP_sha1, 0, },
+       { "hmac-sha1-96",               EVP_sha1, 96 },
+       { "hmac-md5",                   EVP_md5, 0 },
+       { "hmac-md5-96",                EVP_md5, 96 },
+       { "hmac-ripemd160",             EVP_ripemd160, 0 },
+       { "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 },
+       { NULL,                         NULL, 0 }
+};
+
+int
+mac_init(Mac *mac, char *name)
+{
+       int i;
+       for (i = 0; macs[i].name; i++) {
+               if (strcmp(name, macs[i].name) == 0) {
+                       if (mac != NULL) {
+                               mac->md = (*macs[i].mdfunc)();
+                               mac->key_len = mac->mac_len = mac->md->md_size;
+                               if (macs[i].truncatebits != 0)
+                                       mac->mac_len = macs[i].truncatebits/8;
+                       }
+                       debug2("mac_init: found %s", name);
+                       return (0);
+               }
+       }
+       debug2("mac_init: unknown %s", name);
+       return (-1);
+}
+
+u_char *
+mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
+{
+       HMAC_CTX c;
+       static u_char m[EVP_MAX_MD_SIZE];
+       u_char b[4];
+
+       if (mac->key == NULL)
+               fatal("mac_compute: no key");
+       if (mac->mac_len > sizeof(m))
+               fatal("mac_compute: mac too long");
+       HMAC_Init(&c, mac->key, mac->key_len, mac->md);
+       PUT_32BIT(b, seqno);
+       HMAC_Update(&c, b, sizeof(b));
+       HMAC_Update(&c, data, datalen);
+       HMAC_Final(&c, m, NULL);
+       HMAC_cleanup(&c);
+       return (m);
+}
+
+/* XXX copied from ciphers_valid */
+#define        MAC_SEP ","
+int
+mac_valid(const char *names)
+{
+       char *maclist, *cp, *p;
+
+       if (names == NULL || strcmp(names, "") == 0)
+               return (0);
+       maclist = cp = xstrdup(names);
+       for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
+            (p = strsep(&cp, MAC_SEP))) {
+               if (mac_init(NULL, p) < 0) {
+                       debug("bad mac %s [%s]", p, names);
+                       xfree(maclist);
+                       return (0);
+               } else {
+                       debug3("mac ok: %s [%s]", p, names);
+               }
+       }
+       debug3("macs ok: [%s]", names);
+       xfree(maclist);
+       return (1);
+}
diff --git a/openssh/mac.h b/openssh/mac.h
new file mode 100644 (file)
index 0000000..43b485d
--- /dev/null
@@ -0,0 +1,28 @@
+/*      $OpenBSD: mac.h,v 1.3 2001/06/26 17:27:24 markus Exp $   */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int     mac_valid(const char *);
+int     mac_init(Mac *, char *);
+u_char *mac_compute(Mac *, u_int32_t, u_char *, int);
diff --git a/openssh/match.c b/openssh/match.c
new file mode 100644 (file)
index 0000000..188b9a4
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Simple pattern matching, with '*' and '?' as wildcards.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: match.c,v 1.14 2001/06/27 04:48:53 markus Exp $");
+
+#include "match.h"
+#include "xmalloc.h"
+
+/*
+ * Returns true if the given string matches the pattern (which may contain ?
+ * and * as wildcards), and zero if it does not match.
+ */
+
+int
+match_pattern(const char *s, const char *pattern)
+{
+       for (;;) {
+               /* If at end of pattern, accept if also at end of string. */
+               if (!*pattern)
+                       return !*s;
+
+               if (*pattern == '*') {
+                       /* Skip the asterisk. */
+                       pattern++;
+
+                       /* If at end of pattern, accept immediately. */
+                       if (!*pattern)
+                               return 1;
+
+                       /* If next character in pattern is known, optimize. */
+                       if (*pattern != '?' && *pattern != '*') {
+                               /*
+                                * Look instances of the next character in
+                                * pattern, and try to match starting from
+                                * those.
+                                */
+                               for (; *s; s++)
+                                       if (*s == *pattern &&
+                                           match_pattern(s + 1, pattern + 1))
+                                               return 1;
+                               /* Failed. */
+                               return 0;
+                       }
+                       /*
+                        * Move ahead one character at a time and try to
+                        * match at each position.
+                        */
+                       for (; *s; s++)
+                               if (match_pattern(s, pattern))
+                                       return 1;
+                       /* Failed. */
+                       return 0;
+               }
+               /*
+                * There must be at least one more character in the string.
+                * If we are at the end, fail.
+                */
+               if (!*s)
+                       return 0;
+
+               /* Check if the next character of the string is acceptable. */
+               if (*pattern != '?' && *pattern != *s)
+                       return 0;
+
+               /* Move to the next character, both in string and in pattern. */
+               s++;
+               pattern++;
+       }
+       /* NOTREACHED */
+}
+
+/*
+ * Tries to match the host name (which must be in all lowercase) against the
+ * comma-separated sequence of subpatterns (each possibly preceded by ! to
+ * indicate negation).  Returns -1 if negation matches, 1 if there is
+ * a positive match, 0 if there is no match at all.
+ */
+
+int
+match_hostname(const char *host, const char *pattern, u_int len)
+{
+       char sub[1024];
+       int negated;
+       int got_positive;
+       u_int i, subi;
+
+       got_positive = 0;
+       for (i = 0; i < len;) {
+               /* Check if the subpattern is negated. */
+               if (pattern[i] == '!') {
+                       negated = 1;
+                       i++;
+               } else
+                       negated = 0;
+
+               /*
+                * Extract the subpattern up to a comma or end.  Convert the
+                * subpattern to lowercase.
+                */
+               for (subi = 0;
+                    i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
+                    subi++, i++)
+                       sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
+               /* If subpattern too long, return failure (no match). */
+               if (subi >= sizeof(sub) - 1)
+                       return 0;
+
+               /* If the subpattern was terminated by a comma, skip the comma. */
+               if (i < len && pattern[i] == ',')
+                       i++;
+
+               /* Null-terminate the subpattern. */
+               sub[subi] = '\0';
+
+               /* Try to match the subpattern against the host name. */
+               if (match_pattern(host, sub)) {
+                       if (negated)
+                               return -1;              /* Negative */
+                       else
+                               got_positive = 1;       /* Positive */
+               }
+       }
+
+       /*
+        * Return success if got a positive match.  If there was a negative
+        * match, we have already returned -1 and never get here.
+        */
+       return got_positive;
+}
+
+/*
+ * returns 0 if we get a negative match for the hostname or the ip
+ * or if we get no match at all.  returns 1 otherwise.
+ */
+int
+match_host_and_ip(const char *host, const char *ipaddr,
+    const char *patterns)
+{
+       int mhost, mip;
+
+       /* negative ipaddr match */
+       if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1)
+               return 0;
+       /* negative hostname match */
+       if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1)
+               return 0;
+       /* no match at all */
+       if (mhost == 0 && mip == 0)
+               return 0;
+       return 1;
+}
+
+/*
+ * match user, user@host_or_ip, user@host_or_ip_list against pattern
+ */
+int
+match_user(const char *user, const char *host, const char *ipaddr,
+    const char *pattern)
+{
+       char *p, *pat;
+       int ret;
+
+       if ((p = strchr(pattern,'@')) == NULL)
+               return match_pattern(user, pattern);
+
+       pat = xstrdup(pattern);
+       p = strchr(pat, '@');
+       *p++ = '\0';
+
+       if ((ret = match_pattern(user, pat)) == 1)
+               ret = match_host_and_ip(host, ipaddr, p);
+       xfree(pat);
+
+       return ret;
+}
+
+/*
+ * Returns first item from client-list that is also supported by server-list,
+ * caller must xfree() returned string.
+ */
+#define        MAX_PROP        20
+#define        SEP     ","
+char *
+match_list(const char *client, const char *server, u_int *next)
+{
+       char *sproposals[MAX_PROP];
+       char *c, *s, *p, *ret, *cp, *sp;
+       int i, j, nproposals;
+
+       c = cp = xstrdup(client);
+       s = sp = xstrdup(server);
+
+       for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
+            (p = strsep(&sp, SEP)), i++) {
+               if (i < MAX_PROP)
+                       sproposals[i] = p;
+               else
+                       break;
+       }
+       nproposals = i;
+
+       for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
+            (p = strsep(&cp, SEP)), i++) {
+               for (j = 0; j < nproposals; j++) {
+                       if (strcmp(p, sproposals[j]) == 0) {
+                               ret = xstrdup(p);
+                               if (next != NULL)
+                                       *next = (cp == NULL) ?
+                                           strlen(c) : cp - c;
+                               xfree(c);
+                               xfree(s);
+                               return ret;
+                       }
+               }
+       }
+       if (next != NULL)
+               *next = strlen(c);
+       xfree(c);
+       xfree(s);
+       return NULL;
+}
diff --git a/openssh/match.h b/openssh/match.h
new file mode 100644 (file)
index 0000000..f05fe9b
--- /dev/null
@@ -0,0 +1,23 @@
+/*     $OpenBSD: match.h,v 1.9 2001/06/26 06:32:56 itojun Exp $        */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+#ifndef MATCH_H
+#define MATCH_H
+
+int      match_pattern(const char *, const char *);
+int      match_hostname(const char *, const char *, u_int);
+int     match_host_and_ip(const char *, const char *, const char *);
+int     match_user(const char *, const char *, const char *, const char *);
+char   *match_list(const char *, const char *, u_int *);
+
+#endif
diff --git a/openssh/md5crypt.c b/openssh/md5crypt.c
new file mode 100644 (file)
index 0000000..c1479d2
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Ported from FreeBSD to Linux, only minimal changes.  --marekm
+ */
+
+/*
+ * Adapted from shadow-19990607 by Tudor Bosman, tudorb@jm.nu
+ */
+
+#include "includes.h"
+
+RCSID("$Id$");
+
+#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
+
+#include <openssl/md5.h>
+
+static unsigned char itoa64[] =                /* 0 ... 63 => ascii - 64 */
+       "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char    *magic = "$1$"; /*
+                                * This string is magic for
+                                * this algorithm.  Having
+                                * it this way, we can get
+                                * get better later on
+                                */
+
+static void
+to64(char *s, unsigned long v, int n)
+{
+       while (--n >= 0) {
+               *s++ = itoa64[v&0x3f];
+               v >>= 6;
+       }
+}
+
+int
+is_md5_salt(const char *salt)
+{
+       return (!strncmp(salt, magic, strlen(magic)));
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *
+md5_crypt(const char *pw, const char *salt)
+{
+       static char     passwd[120], *p;
+       static const char *sp,*ep;
+       unsigned char   final[16];
+       int sl,pl,i,j;
+       MD5_CTX ctx,ctx1;
+       unsigned long l;
+
+       /* Refine the Salt first */
+       sp = salt;
+
+       /* If it starts with the magic string, then skip that */
+       if(!strncmp(sp,magic,strlen(magic)))
+               sp += strlen(magic);
+
+       /* It stops at the first '$', max 8 chars */
+       for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+               continue;
+
+       /* get the length of the true salt */
+       sl = ep - sp;
+
+       MD5_Init(&ctx);
+
+       /* The password first, since that is what is most unknown */
+       MD5_Update(&ctx,pw,strlen(pw));
+
+       /* Then our magic string */
+       MD5_Update(&ctx,magic,strlen(magic));
+
+       /* Then the raw salt */
+       MD5_Update(&ctx,sp,sl);
+
+       /* Then just as many characters of the MD5(pw,salt,pw) */
+       MD5_Init(&ctx1);
+       MD5_Update(&ctx1,pw,strlen(pw));
+       MD5_Update(&ctx1,sp,sl);
+       MD5_Update(&ctx1,pw,strlen(pw));
+       MD5_Final(final,&ctx1);
+       for(pl = strlen(pw); pl > 0; pl -= 16)
+               MD5_Update(&ctx,final,pl>16 ? 16 : pl);
+
+       /* Don't leave anything around in vm they could use. */
+       memset(final,0,sizeof final);
+
+       /* Then something really weird... */
+       for (j=0,i = strlen(pw); i ; i >>= 1)
+               if(i&1)
+                   MD5_Update(&ctx, final+j, 1);
+               else
+                   MD5_Update(&ctx, pw+j, 1);
+
+       /* Now make the output string */
+       strcpy(passwd,magic);
+       strncat(passwd,sp,sl);
+       strcat(passwd,"$");
+
+       MD5_Final(final,&ctx);
+
+       /*
+        * and now, just to make sure things don't run too fast
+        * On a 60 Mhz Pentium this takes 34 msec, so you would
+        * need 30 seconds to build a 1000 entry dictionary...
+        */
+       for(i=0;i<1000;i++) {
+               MD5_Init(&ctx1);
+               if(i & 1)
+                       MD5_Update(&ctx1,pw,strlen(pw));
+               else
+                       MD5_Update(&ctx1,final,16);
+
+               if(i % 3)
+                       MD5_Update(&ctx1,sp,sl);
+
+               if(i % 7)
+                       MD5_Update(&ctx1,pw,strlen(pw));
+
+               if(i & 1)
+                       MD5_Update(&ctx1,final,16);
+               else
+                       MD5_Update(&ctx1,pw,strlen(pw));
+               MD5_Final(final,&ctx1);
+       }
+
+       p = passwd + strlen(passwd);
+
+       l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
+       l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
+       l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
+       l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
+       l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
+       l =                    final[11]                ; to64(p,l,2); p += 2;
+       *p = '\0';
+
+       /* Don't leave anything around in vm they could use. */
+       memset(final,0,sizeof final);
+
+       return passwd;
+}
+
+#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
diff --git a/openssh/md5crypt.h b/openssh/md5crypt.h
new file mode 100644 (file)
index 0000000..a134ed0
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Ported from FreeBSD to Linux, only minimal changes.  --marekm
+ */
+
+/*
+ * Adapted from shadow-19990607 by Tudor Bosman, tudorb@jm.nu
+ */
+
+/* $Id$ */
+
+#ifndef _MD5CRYPT_H
+#define _MD5CRYPT_H
+
+#include "config.h"
+
+#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
+
+int is_md5_salt(const char *salt);
+char *md5_crypt(const char *pw, const char *salt);
+
+#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
+
+#endif /* MD5CRYPT_H */
diff --git a/openssh/mdoc2man.pl b/openssh/mdoc2man.pl
new file mode 100644 (file)
index 0000000..fddb2e0
--- /dev/null
@@ -0,0 +1,590 @@
+#!/usr/bin/perl
+###
+### Quick usage:  mdoc2man.pl < mdoc_manpage.8 > man_manpage.8
+###
+###
+###  Copyright (c) 2001 University of Illinois Board of Trustees
+###  Copyright (c) 2001 Mark D. Roth
+###  All rights reserved.
+### 
+###  Redistribution and use in source and binary forms, with or without
+###  modification, are permitted provided that the following conditions
+###  are met:
+###  1. Redistributions of source code must retain the above copyright
+###     notice, this list of conditions and the following disclaimer.
+###  2. Redistributions in binary form must reproduce the above copyright
+###     notice, this list of conditions and the following disclaimer in the
+###     documentation and/or other materials provided with the distribution.
+###  3. All advertising materials mentioning features or use of this software
+###     must display the following acknowledgement:
+###     This product includes software developed by the University of
+###     Illinois at Urbana, and their contributors.
+###  4. The University nor the names of their
+###     contributors may be used to endorse or promote products derived from
+###     this software without specific prior written permission.
+### 
+###  THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS ``AS IS'' AND
+###  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+###  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+###  ARE DISCLAIMED.  IN NO EVENT SHALL THE TRUSTEES OR CONTRIBUTORS BE LIABLE
+###  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+###  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+###  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+###  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+###  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+###  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+###  SUCH DAMAGE.
+###
+
+use strict;
+
+my ($name, $date, $id);
+my ($line);
+my ($optlist, $oldoptlist, $nospace, $enum, $synopsis);
+my ($reference, $block, $ext, $extopt, $literal);
+my (@refauthors, $reftitle, $refissue, $refdate, $refopt);
+
+
+$optlist = 0;          ### 1 = bullet, 2 = enum, 3 = tag, 4 = item
+$oldoptlist = 0;
+$nospace = 0;
+$synopsis = 0;
+$reference = 0;
+$block = 0;
+$ext = 0;
+$extopt = 0;
+$literal = 0;
+
+while ($line = <STDIN>)
+{
+       if ($line !~ /^\./)
+       {
+               print $line;
+               print ".br\n"
+                       if ($literal);
+               next;
+       }
+
+       $line =~ s/^\.//;
+
+       next
+               if ($line =~ m/\\"/);
+
+       $line = ParseMacro($line);
+       print($line)
+               if (defined $line);
+}
+
+
+
+sub ParseMacro # ($line)
+{
+       my ($line) = @_;
+       my (@words, $retval, $option, $parens);
+
+       @words = split(/\s+/, $line);
+       $retval = '';
+       $option = 0;
+       $parens = 0;
+
+#      print('@words = ', scalar(@words), ': ', join(' ', @words), "\n");
+
+       while ($_ = shift @words)
+       {
+#              print "WORD: $_\n";
+
+               next
+                       if (/^(Li|Pf)$/);
+
+               if (/^Xo$/)
+               {
+                       $ext = 1;
+                       $retval .= ' '
+                               if ($retval ne '' && $retval !~ m/[\n ]$/);
+                       next;
+               }
+
+               if (/^Xc$/)
+               {
+                       $ext = 0;
+                       $retval .= "\n"
+                               if (! $extopt);
+                       last;
+               }
+
+               if (/^Bd$/)
+               {
+                       $literal = 1
+                               if ($words[0] eq '-literal');
+                       $retval .= "\n";
+                       last;
+               }
+
+               if (/^Ed$/)
+               {
+                       $literal = 0;
+                       last;
+               }
+
+               if (/^Ns$/)
+               {
+                       $nospace = 1
+                               if (! $nospace);
+                       $retval =~ s/ $//;
+                       next;
+               }
+
+               if (/^No$/)
+               {
+                       $retval =~ s/ $//;
+                       $retval .= shift @words;
+                       next;
+               }
+
+               if (/^Dq$/)
+               {
+                       $retval .= '``';
+                       do
+                       {
+                               $retval .= (shift @words) . ' ';
+                       }
+                       while (@words > 0 && $words[0] !~ m/^[\.,]/);
+                       $retval =~ s/ $//;
+                       $retval .= '\'\'';
+                       $nospace = 1
+                               if (! $nospace && $words[0] =~ m/^[\.,]/);
+                       next;
+               }
+
+               if (/^(Sq|Ql)$/)
+               {
+                       $retval .= '`' . (shift @words) . '\'';
+                       $nospace = 1
+                               if (! $nospace && $words[0] =~ m/^[\.,]/);
+                       next;
+               }
+
+#              if (/^Ic$/)
+#              {
+#                      $retval .= '\\fB' . shift(@words) . '\\fP';
+#                      next;
+#              }
+
+               if (/^Oo$/)
+               {
+#                      $retval .= "[\\c\n";
+                       $extopt = 1;
+                       $nospace = 1
+                               if (! $nospace);
+                       $retval .= '[';
+                       next;
+               }
+
+               if (/^Oc$/)
+               {
+                       $extopt = 0;
+                       $retval .= ']';
+                       next;
+               }
+
+               $retval .= ' '
+                       if (! $nospace && $retval ne '' && $retval !~ m/[\n ]$/);
+               $nospace = 0
+                       if ($nospace == 1);
+
+               if (/^Dd$/)
+               {
+                       $date = join(' ', @words);
+                       return undef;
+               }
+
+               if (/^Dt$/)
+               {
+                       $id = join(' ', @words);
+                       return undef;
+               }
+
+               if (/^Os$/)
+               {
+                       $retval .= '.TH '
+                               . $id
+                               . " \"$date\" \""
+                               . join(' ', @words)
+                               . "\"";
+                       last;
+               }
+
+               if (/^Sh$/)
+               {
+                       $retval .= '.SH';
+                       if ($words[0] eq 'SYNOPSIS')
+                       {
+                               $synopsis = 1;
+                       }
+                       else
+                       {
+                               $synopsis = 0;
+                       }
+                       next;
+               }
+
+               if (/^Xr$/)
+               {
+                       $retval .= '\\fB' . (shift @words) .
+                               '\\fP(' . (shift @words) . ')'
+                               . (shift @words);
+                       last;
+               }
+
+               if (/^Rs/)
+               {
+                       @refauthors = ();
+                       $reftitle = '';
+                       $refissue = '';
+                       $refdate = '';
+                       $refopt = '';
+                       $reference = 1;
+                       last;
+               }
+
+               if (/^Re/)
+               {
+                       $retval .= "\n";
+
+                       # authors
+                       while (scalar(@refauthors) > 1)
+                       {
+                               $retval .= shift(@refauthors) . ', ';
+                       }
+                       $retval .= 'and '
+                               if ($retval ne '');
+                       $retval .= shift(@refauthors);
+                       
+                       # title 
+                       $retval .= ', \\fI' . $reftitle . '\\fP';
+
+                       # issue
+                       $retval .= ', ' . $refissue
+                               if ($refissue ne '');
+
+                       # date
+                       $retval .= ', ' . $refdate
+                               if ($refdate ne '');
+
+                       # optional info
+                       $retval .= ', ' . $refopt
+                               if ($refopt ne '');
+
+                       $retval .= ".\n";
+
+                       $reference = 0;
+                       last;
+               }
+
+               if ($reference)
+               {
+                       if (/^%A$/)
+                       {
+                               unshift(@refauthors, join(' ', @words));
+                               last;
+                       }
+
+                       if (/^%T$/)
+                       {
+                               $reftitle = join(' ', @words);
+                               $reftitle =~ s/^"//;
+                               $reftitle =~ s/"$//;
+                               last;
+                       }
+
+                       if (/^%N$/)
+                       {
+                               $refissue = join(' ', @words);
+                               last;
+                       }
+
+                       if (/^%D$/)
+                       {
+                               $refdate = join(' ', @words);
+                               last;
+                       }
+
+                       if (/^%O$/)
+                       {
+                               $refopt = join(' ', @words);
+                               last;
+                       }
+               }
+
+               if (/^Nm$/)
+               {
+                       $name = shift @words
+                               if (@words > 0);
+                       $retval .= ".br\n"
+                               if ($synopsis);
+                       $retval .= "\\fB$name\\fP";
+                       $nospace = 1
+                               if (! $nospace && $words[0] =~ m/^[\.,]/);
+                       next;
+               }
+
+               if (/^Nd$/)
+               {
+                       $retval .= '\\-';
+                       next;
+               }
+
+               if (/^Fl$/)
+               {
+                       $retval .= '\\fB\\-' . (shift @words) . '\\fP';
+                       $nospace = 1
+                               if (! $nospace && $words[0] =~ m/^[\.,]/);
+                       next;
+               }
+
+               if (/^Ar$/)
+               {
+                       $retval .= '\\fI';
+                       if (! defined $words[0])
+                       {
+                               $retval .= 'file ...\\fP';
+                       }
+                       else
+                       {
+                               $retval .= shift(@words) . '\\fP';
+                               while ($words[0] eq '|')
+                               {
+                                       $retval .= ' ' . shift(@words);
+                                       $retval .= ' \\fI' . shift(@words);
+                                       $retval .= '\\fP';
+                               }
+                       }
+                       $nospace = 1
+                               if (! $nospace && $words[0] =~ m/^[\.,]/);
+                       next;
+               }
+
+               if (/^Cm$/)
+               {
+                       $retval .= '\\fB' . (shift @words) . '\\fP';
+                       while ($words[0] =~ m/^[\.,:)]$/)
+                       {
+                               $retval .= shift(@words);
+                       }
+                       next;
+               }
+
+               if (/^Op$/)
+               {
+                       $option = 1;
+                       $nospace = 1
+                               if (! $nospace);
+                       $retval .= '[';
+#                      my $tmp = pop(@words);
+#                      $tmp .= ']';
+#                      push(@words, $tmp);
+                       next;
+               }
+
+               if (/^Pp$/)
+               {
+                       $retval .= "\n";
+                       next;
+               }
+
+               if (/^Ss$/)
+               {
+                       $retval .= '.SS';
+                       next;
+               }
+
+               if (/^Pa$/ && ! $option)
+               {
+                       $retval .= '\\fI';
+                       $retval .= '\\&'
+                               if ($words[0] =~ m/^\./);
+                       $retval .= (shift @words) . '\\fP';
+                       while ($words[0] =~ m/^[\.,:;)]$/)
+                       {
+                               $retval .= shift(@words);
+                       }
+#                      $nospace = 1
+#                              if (! $nospace && $words[0] =~ m/^[\.,:)]/);
+                       next;
+               }
+
+               if (/^Dv$/)
+               {
+                       $retval .= '.BR';
+                       next;
+               }
+
+               if (/^(Em|Ev)$/)
+               {
+                       $retval .= '.IR';
+                       next;
+               }
+
+               if (/^Pq$/)
+               {
+                       $retval .= '(';
+                       $nospace = 1;
+                       $parens = 1;
+                       next;
+               }
+
+               if (/^(S[xy])$/)
+               {
+                       $retval .= '.B ' . join(' ', @words);
+                       last;
+               }
+
+               if (/^Ic$/)
+               {
+                       $retval .= '\\fB';
+                       while (defined $words[0]
+                               && $words[0] !~ m/^[\.,]/)
+                       {
+                               if ($words[0] eq 'Op')
+                               {
+                                       shift(@words);
+                                       $retval .= '[';
+                                       my $tmp = pop(@words);
+                                       $tmp .= ']';
+                                       push(@words, $tmp);
+                                       next;
+                               }
+                               if ($words[0] eq 'Ar')
+                               {
+                                       shift @words;
+                                       $retval .= '\\fI';
+                                       $retval .= shift @words;
+                                       $retval .= '\\fP';
+                               }
+                               else
+                               {
+                                       $retval .= shift @words;
+                               }
+                               $retval .= ' '
+                                       if (! $nospace);
+                       }
+                       $retval =~ s/ $//;
+                       $retval .= '\\fP';
+                       $retval .= shift @words
+                               if (defined $words[0]);
+                       last;
+               }
+
+               if (/^Bl$/)
+               {
+                       $oldoptlist = $optlist;
+                       if ($words[0] eq '-bullet')
+                       {
+                               $optlist = 1;
+                       }
+                       elsif ($words[0] eq '-enum')
+                       {
+                               $optlist = 2;
+                               $enum = 0;
+                       }
+                       elsif ($words[0] eq '-tag')
+                       {
+                               $optlist = 3;
+                       }
+                       elsif ($words[0] eq '-item')
+                       {
+                               $optlist = 4;
+                       }
+                       last;
+               }
+
+               if (/^El$/)
+               {
+                       $optlist = $oldoptlist;
+                       next;
+               }
+
+               if ($optlist && /^It$/)
+               {
+                       if ($optlist == 1)
+                       {
+                               # bullets
+                               $retval .= '.IP \\(bu';
+                               next;
+                       }
+
+                       if ($optlist == 2)
+                       {
+                               # enum
+                               $retval .= '.IP ' . (++$enum) . '.';
+                               next;
+                       }
+
+                       if ($optlist == 3)
+                       {
+                               # tags
+                               $retval .= ".TP\n";
+                               if ($words[0] =~ m/^(Pa|Ev)$/)
+                               {
+                                       shift @words;
+                                       $retval .= '.B';
+                               }
+                               next;
+                       }
+
+                       if ($optlist == 4)
+                       {
+                               # item
+                               $retval .= ".IP\n";
+                               next;
+                       }
+
+                       next;
+               }
+
+               if (/^Sm$/)
+               {
+                       if ($words[0] eq 'off')
+                       {
+                               $nospace = 2;
+                       }
+                       elsif ($words[0] eq 'on')
+                       {
+#                              $retval .= "\n";
+                               $nospace = 0;
+                       }
+                       shift @words;
+                       next;
+               }
+
+               $retval .= "$_";
+       }
+
+       return undef
+               if ($retval eq '.');
+
+       $retval =~ s/^\.([^a-zA-Z])/$1/;
+#      $retval =~ s/ $//;
+
+       $retval .= ')'
+               if ($parens == 1);
+
+       $retval .= ']'
+               if ($option == 1);
+
+#      $retval .= ' '
+#              if ($nospace && $retval ne '' && $retval !~ m/\n$/);
+
+#      $retval .= ' '
+#              if ($extended && $retval !~ m/ $/);
+
+       $retval .= ' '
+               if ($ext && ! $extopt && $retval !~ m/ $/);
+
+       $retval .= "\n"
+               if (! $ext && ! $extopt && $retval ne '' && $retval !~ m/\n$/);
+
+       return $retval;
+}
+
+
diff --git a/openssh/misc.c b/openssh/misc.c
new file mode 100644 (file)
index 0000000..620121f
--- /dev/null
@@ -0,0 +1,333 @@
+/*     $OpenBSD: misc.c,v 1.12 2001/06/26 17:27:24 markus Exp $        */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: misc.c,v 1.12 2001/06/26 17:27:24 markus Exp $");
+
+#include "misc.h"
+#include "log.h"
+#include "xmalloc.h"
+
+/* remove newline at end of string */
+char *
+chop(char *s)
+{
+       char *t = s;
+       while (*t) {
+               if(*t == '\n' || *t == '\r') {
+                       *t = '\0';
+                       return s;
+               }
+               t++;
+       }
+       return s;
+
+}
+
+/* set/unset filedescriptor to non-blocking */
+void
+set_nonblock(int fd)
+{
+       int val;
+
+       val = fcntl(fd, F_GETFL, 0);
+       if (val < 0) {
+               error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
+               return;
+       }
+       if (val & O_NONBLOCK) {
+               debug2("fd %d is O_NONBLOCK", fd);
+               return;
+       }
+       debug("fd %d setting O_NONBLOCK", fd);
+       val |= O_NONBLOCK;
+       if (fcntl(fd, F_SETFL, val) == -1)
+               if (errno != ENODEV)
+                       error("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
+                           fd, strerror(errno));
+}
+
+void
+unset_nonblock(int fd)
+{
+       int val;
+
+       val = fcntl(fd, F_GETFL, 0);
+       if (val < 0) {
+               error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
+               return;
+       }
+       if (!(val & O_NONBLOCK)) {
+               debug2("fd %d is not O_NONBLOCK", fd);
+               return;
+       }
+       debug("fd %d clearing O_NONBLOCK", fd);
+       val &= ~O_NONBLOCK;
+       if (fcntl(fd, F_SETFL, val) == -1)
+               if (errno != ENODEV)
+                       error("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
+                           fd, strerror(errno));
+}
+
+/* Characters considered whitespace in strsep calls. */
+#define WHITESPACE " \t\r\n"
+
+/* return next token in configuration line */
+char *
+strdelim(char **s)
+{
+       char *old;
+       int wspace = 0;
+
+       if (*s == NULL)
+               return NULL;
+
+       old = *s;
+
+       *s = strpbrk(*s, WHITESPACE "=");
+       if (*s == NULL)
+               return (old);
+
+       /* Allow only one '=' to be skipped */
+       if (*s[0] == '=')
+               wspace = 1;
+       *s[0] = '\0';
+
+       *s += strspn(*s + 1, WHITESPACE) + 1;
+       if (*s[0] == '=' && !wspace)
+               *s += strspn(*s + 1, WHITESPACE) + 1;
+
+       return (old);
+}
+
+struct passwd *
+pwcopy(struct passwd *pw)
+{
+       struct passwd *copy = xmalloc(sizeof(*copy));
+
+       memset(copy, 0, sizeof(*copy));
+       copy->pw_name = xstrdup(pw->pw_name);
+       copy->pw_passwd = xstrdup(pw->pw_passwd);
+       copy->pw_gecos = xstrdup(pw->pw_gecos);
+       copy->pw_uid = pw->pw_uid;
+       copy->pw_gid = pw->pw_gid;
+#ifdef HAVE_PW_EXPIRE_IN_PASSWD
+       copy->pw_expire = pw->pw_expire;
+#endif
+#ifdef HAVE_PW_CHANGE_IN_PASSWD
+       copy->pw_change = pw->pw_change;
+#endif
+#ifdef HAVE_PW_CLASS_IN_PASSWD
+       copy->pw_class = xstrdup(pw->pw_class);
+#endif
+       copy->pw_dir = xstrdup(pw->pw_dir);
+       copy->pw_shell = xstrdup(pw->pw_shell);
+       return copy;
+}
+
+/*
+ * Convert ASCII string to TCP/IP port number.
+ * Port must be >0 and <=65535.
+ * Return 0 if invalid.
+ */
+int
+a2port(const char *s)
+{
+       long port;
+       char *endp;
+
+       errno = 0;
+       port = strtol(s, &endp, 0);
+       if (s == endp || *endp != '\0' ||
+           (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
+           port <= 0 || port > 65535)
+               return 0;
+
+       return port;
+}
+
+#define SECONDS                1
+#define MINUTES                (SECONDS * 60)
+#define HOURS          (MINUTES * 60)
+#define DAYS           (HOURS * 24)
+#define WEEKS          (DAYS * 7)
+
+/*
+ * Convert a time string into seconds; format is
+ * a sequence of:
+ *      time[qualifier]
+ *
+ * Valid time qualifiers are:
+ *      <none>  seconds
+ *      s|S     seconds
+ *      m|M     minutes
+ *      h|H     hours
+ *      d|D     days
+ *      w|W     weeks
+ *
+ * Examples:
+ *      90m     90 minutes
+ *      1h30m   90 minutes
+ *      2d      2 days
+ *      1w      1 week
+ *
+ * Return -1 if time string is invalid.
+ */
+long
+convtime(const char *s)
+{
+       long total, secs;
+       const char *p;
+       char *endp;
+
+       errno = 0;
+       total = 0;
+       p = s;
+
+       if (p == NULL || *p == '\0')
+               return -1;
+
+       while (*p) {
+               secs = strtol(p, &endp, 10);
+               if (p == endp ||
+                   (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
+                   secs < 0)
+                       return -1;
+
+               switch (*endp++) {
+               case '\0':
+                       endp--;
+               case 's':
+               case 'S':
+                       break;
+               case 'm':
+               case 'M':
+                       secs *= MINUTES;
+                       break;
+               case 'h':
+               case 'H':
+                       secs *= HOURS;
+                       break;
+               case 'd':
+               case 'D':
+                       secs *= DAYS;
+                       break;
+               case 'w':
+               case 'W':
+                       secs *= WEEKS;
+                       break;
+               default:
+                       return -1;
+               }
+               total += secs;
+               if (total < 0)
+                       return -1;
+               p = endp;
+       }
+
+       return total;
+}
+
+char *
+cleanhostname(char *host)
+{
+       if (*host == '[' && host[strlen(host) - 1] == ']') {
+               host[strlen(host) - 1] = '\0';
+               return (host + 1);
+       } else
+               return host;
+}
+
+char *
+colon(char *cp)
+{
+       int flag = 0;
+
+       if (*cp == ':')         /* Leading colon is part of file name. */
+               return (0);
+       if (*cp == '[')
+               flag = 1;
+
+       for (; *cp; ++cp) {
+               if (*cp == '@' && *(cp+1) == '[')
+                       flag = 1;
+               if (*cp == ']' && *(cp+1) == ':' && flag)
+                       return (cp+1);
+               if (*cp == ':' && !flag)
+                       return (cp);
+               if (*cp == '/')
+                       return (0);
+       }
+       return (0);
+}
+
+/* function to assist building execv() arguments */
+void
+addargs(arglist *args, char *fmt, ...)
+{
+       va_list ap;
+       char buf[1024];
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       if (args->list == NULL) {
+               args->nalloc = 32;
+               args->num = 0;
+       } else if (args->num+2 >= args->nalloc) 
+               args->nalloc *= 2;
+
+       args->list = xrealloc(args->list, args->nalloc * sizeof(char *));
+       args->list[args->num++] = xstrdup(buf);
+       args->list[args->num] = NULL;
+}
+
+mysig_t
+mysignal(int sig, mysig_t act)
+{
+#ifdef HAVE_SIGACTION
+       struct sigaction sa, osa;
+
+       if (sigaction(sig, NULL, &osa) == -1)
+               return (mysig_t) -1;
+       if (osa.sa_handler != act) {
+               memset(&sa, 0, sizeof(sa));
+               sigemptyset(&sa.sa_mask);
+               sa.sa_flags = 0;
+#if defined(SA_INTERRUPT)
+               if (sig == SIGALRM)
+                       sa.sa_flags |= SA_INTERRUPT;
+#endif
+               sa.sa_handler = act;
+               if (sigaction(sig, &sa, NULL) == -1)
+                       return (mysig_t) -1;
+       }
+       return (osa.sa_handler);
+#else
+       return (signal(sig, act));
+#endif
+}
diff --git a/openssh/misc.h b/openssh/misc.h
new file mode 100644 (file)
index 0000000..fc56452
--- /dev/null
@@ -0,0 +1,36 @@
+/*     $OpenBSD: misc.h,v 1.10 2001/06/26 17:27:24 markus Exp $        */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+char   *chop(char *);
+char   *strdelim(char **);
+void    set_nonblock(int);
+void    unset_nonblock(int);
+int     a2port(const char *);
+char   *cleanhostname(char *);
+char   *colon(char *);
+long    convtime(const char *);
+
+struct passwd *pwcopy(struct passwd *);
+
+typedef struct arglist arglist;
+struct arglist {
+        char    **list;
+        int     num;
+        int     nalloc;
+};
+void    addargs(arglist *, char *, ...) __attribute__((format(printf, 2, 3)));
+
+/* wrapper for signal interface */
+typedef void (*mysig_t)(int);
+mysig_t mysignal(int sig, mysig_t act);
diff --git a/openssh/mkinstalldirs b/openssh/mkinstalldirs
new file mode 100755 (executable)
index 0000000..6b3b5fc
--- /dev/null
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+         errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/openssh/moduli b/openssh/moduli
new file mode 100644 (file)
index 0000000..6b94e2e
--- /dev/null
@@ -0,0 +1,158 @@
+#      $OpenBSD: moduli,v 1.1 2001/06/22 22:07:54 provos Exp $
+
+# Time Type Tests Tries Size Generator Modulus
+20010328182134 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF5449C221CB
+20010328182222 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF5449C95A43
+20010328182256 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF5449CC8CFB
+20010328182409 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF5449D9BDB7
+20010328182628 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF5449FB6EF3
+20010328182708 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A000153
+20010328182758 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A06E9EB
+20010328182946 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A1F2C93
+20010328183015 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A206ADB
+20010328183112 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A2A109B
+20010328183143 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A2BC1BB
+20010328183301 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A3ADCEB
+20010328183532 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A5E8BAF
+20010328183646 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A6D54D7
+20010328183712 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544A6EC46F
+20010328184223 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544AB8626F
+20010328184337 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544AC7DC73
+20010328184634 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544AEFF073
+20010328184714 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544AF594FF
+20010328184807 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544AFEEC53
+20010328184910 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B0B3513
+20010328185030 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B165707
+20010328185334 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B3A9673
+20010328185423 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B426623
+20010328185451 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B4427DB
+20010328185637 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B5E3FC7
+20010328185720 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B65964B
+20010328185757 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B6A9373
+20010328185844 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B7203B3
+20010328185933 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B7A9FFF
+20010328190006 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B7DAAD3
+20010328190054 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B855C2F
+20010328190139 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B8C53EB
+20010328190304 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544B9F26C3
+20010328190329 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544BA00697
+20010328190412 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544BA54313
+20010328190506 2 6 100 1023 5 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544BAEEF27
+20010328190550 2 6 100 1023 2 DCFAC4EFE89F5B082962AB9A67E8D63E84FA491E5D3874978815868595469163DA0661E6208A8C2CD4F83893B53864ADFD2154E8D8EFA146BAD808562E4BF6C90348FD79EEB3387D93FC7943BC450BA55399BA3CF3DFBD0D4E71800007B0E9D5F12E7A2CB7EA4E49812E715F8DC570C478DC2DEB1C49B0AE87A5DF544BB5CE0B
+20010328200734 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC33395187
+20010328201124 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC334ED15B
+20010328201358 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3359FC07
+20010328201537 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC335F7A83
+20010328201829 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC336D1433
+20010328202120 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC337B253B
+20010328202848 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC33A3D43F
+20010328203335 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC33BF24A3
+20010328204332 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC34011B8B
+20010328204443 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3402A92F
+20010328204617 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3406D343
+20010328205458 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3436FA2B
+20010328210413 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3471CF1B
+20010328213513 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC352AF5EF
+20010328215014 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC358CC3CB
+20010328215520 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35A9B7FF
+20010328215733 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35B2927F
+20010328220114 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35C47323
+20010328220334 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35CFA9C3
+20010328220653 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35E0BB37
+20010328220915 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35E9CC23
+20010328221256 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC35FD7D67
+20010328221457 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC36052CCB
+20010328222639 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC364A1E07
+20010328224126 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC36AD5557
+20010328225125 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC36EE57BF
+20010328225751 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3716A70B
+20010328225943 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC371D010B
+20010328230054 2 6 100 1534 5 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC371EB5C7
+20010328230301 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC37275F4B
+20010328230628 2 6 100 1534 2 6DFD16D9669EDAF42EF5D4EED82AA84B0541DEC2045B6AF55021A184F32BCADE614A114137022C9A8B41C09AFC38199E7305864F70A8708F37FC2127264ECF4FA32391F243CC62B89602D3813082679E5BDF496BA9DFA4C818AD21EC261B6F11841E6F2DE1574CE95095841DAF052868CCD5E9BFCA543E0934B50A76A598E693136DE2D479AEF3785D97BAFF4FB85AB8D46DA424C4CC5E11ABCAF718837E16350982BF8A27728318EC02C71ED164F57CDB121B72614B7B7C406613EC3738C3F3
+20010329000424 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853ACAACAB
+20010329001637 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853AE5BE0F
+20010329002229 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853AEDE2D3
+20010329003652 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853B0F32CB
+20010329005040 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853B30E503
+20010329014643 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853BC9AF57
+20010329021950 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853C205263
+20010329023256 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853C3F2E53
+20010329031049 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853CA28BBF
+20010329032045 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853CB81103
+20010329052113 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853DF13B47
+20010329052449 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853DF3ED53
+20010329060404 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853E5D25E7
+20010329062856 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853E9CF013
+20010329063152 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853E9E1CEB
+20010329070601 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853EF58B7F
+20010329071302 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853F017697
+20010329072011 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853F0E72D3
+20010329072445 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853F14CE17
+20010329073641 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853F2EEBA3
+20010329075209 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853F52E927
+20010329080750 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853F776F8B
+20010329084002 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853FC98043
+20010329084744 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853FD7EAAF
+20010329090209 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993853FF9AF5F
+20010329093527 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC3499385404E330B
+20010329094652 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC349938540672D1F
+20010329103445 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC349938540E4B213
+20010329111418 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC34993854144947F
+20010329112031 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC3499385414F223B
+20010329112413 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC349938541522073
+20010329114209 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC3499385417C8E53
+20010329125026 2 6 100 2046 2 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC3499385422E41AB
+20010329132045 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC3499385427DD3FF
+20010329134105 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC349938542AFA2D7
+20010329134914 2 6 100 2046 5 7ED0888B660A818F15E5F76A7F2BF10C99D74129DA04446C60116C9C800501060B8AFF075DCE0C08CEFDF695440E6F16FCCDB06359D080EF62D6485CBAEB94B92BE771D535B4EA9C5D14D84CD7649E25C7CFEA2C914486CC2BFDE77C4C0DF1D6DDED65FEE2F53A7FA690AFE38EE00C154FBAEFF935466B176CB0AED02458A552929F4EA7FC3E6F9F758DE7F22CC1F49641F492820441BDC109F0CE18F883FC93EA9AC4C1432682BA1C5B67BED8C861152A5F952A8CDCF1BCE02B8D93E80C113CE9FE2E4ACA49B2978B99A8C5FA231A77F5E7C604D44C7C6EA98D561294D4F7AB061432CAB8BBDCEC3659DE64F65265E6B9FC5F46879BB17CC349938542C04A37
+20010403222140 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0AB16DAF
+20010403225231 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0AC56CFF
+20010404053436 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0C2F4B7F
+20010404092851 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0D04E7F7
+20010404093943 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0D07794B
+20010404102659 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0D2BE8CF
+20010404112553 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0D5D012B
+20010404174625 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0EA59E17
+20010404184645 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0ED6DA4F
+20010404193402 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0EFB39B3
+20010404230716 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B0FB07C1B
+20010405044433 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B10DD9FC3
+20010405053429 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B11038737
+20010405062826 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B112E24E7
+20010405092601 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B11C9E9FB
+20010405113007 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B123803EB
+20010405122212 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B12612ED3
+20010405182035 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B13A25087
+20010405210758 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B142C4E23
+20010405220222 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B145878F3
+20010406020130 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B152AF6AB
+20010406053538 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B15E78C8B
+20010406073014 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1649BFEF
+20010406074100 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B164D4E3F
+20010406103625 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B16E07B33
+20010406131946 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B17706243
+20010406170234 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B182FD957
+20010406182949 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B18768903
+20010406203157 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B18DCFC3B
+20010407022825 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1A1AF797
+20010407071024 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1B1551E7
+20010407112402 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1BF78EC7
+20010407123215 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1C30021B
+20010407161504 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1CF27743
+20010407171629 2 6 100 3190 5 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1D25FAD7
+20010407191502 2 6 100 3190 2 669BA3ED661F226A090BE5644A2BB4209371B78FC3E6848A095821993F59084CA5EE12052F977D01F0666F03F6573B199DFEC9AB94588C2C60DE3B3E7CF5094587919FCC3FB40A61C261E891A0F91D9FFC8F30CA12CF809DD8290DD786FA8B041FFAC5793C38F38757EA6790472AC2692185B554B0046E8C065C983C0ACC8D2F85AB4BEDF7CE233009218C9691FE44261580D4149F1D4471B0B5DF79E224252474EBC3B7B5490950BB438BF498E79F8794498B3A3B5FBB42829C3BBEA4067F28C23BE40377B986BD5443CCCF02405B8CCCAA09E8179F0168D4969994171A6AD98F81015BC84E10A44E1EFD2E0862C5D1AAFE99014715A36800DBD9A6C51C0226CC82A651DAE4F73D54C4D103C13D1C15CF8CCA67D5CB39F03C66F3B7467F8FFDCC5074CD0C1B2538FBF956971BF39314CEDD20E1B10DE16D86E10BE7FA5B1A706AEB4C356F49807A22072CD00559AF0A863788956651919E26A315EAD1D26E7C98FC4CFA35A0F04DD400A2991A1FFE5B271FEDE54375896A29F968BE1D511BA466A92AC3E3772709FC815B1D8C2753
+20010420002705 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10C1E08F3
+20010420005243 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10C219FB3
+20010420035225 2 6 100 4094 5 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10C660B3F
+20010420145749 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10D741313
+20010420205718 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10DD41193
+20010420232458 2 6 100 4094 5 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10E0AB4EF
+20010421003952 2 6 100 4094 5 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10E22F857
+20010421013245 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10E31828B
+20010421085157 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10EE28B2B
+20010421092617 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10EE97A3B
+20010421135621 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C10F52C463
+20010422012438 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C110627AF3
+20010422042530 2 6 100 4094 2 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C110A793B3
+20010422163438 2 6 100 4094 5 65B5B9F5ECFADB4CCB38D1BC894302E95B4843290F1A7A40579DF3E2FF98C1D3DA9F210857C784433DF32ADF9E0C80121211690E1FFB41B8DB4E86AFE388A09C9BB2C98EDC581C2E65D57F61BB920C3D1B7B058B5FADFF65D607DAFF443B8BA1ACE1A3A7B16EA0713F62537C6689E3C4A0F61198F3B054FCF140CFADD8622C0E7621998331E59DA6F72E9D608D0E58F526E95F485C7CA30A416617DA3CCFF722BB82362606283D054B34B83ECDB4C91BAB835944010EBE5E9FA7B016ED89891DD553CC71B5CF76EDB2A184B377F670D6AF191763EEFD175E48EA37EE18B9E44E2D017D845C444C8111816819866E490B52F7F879A0C6F401CF7859674F93E304365F4E8CB8C312EFB725732A46D7CF0C9D2939AEE25F428CEFC90959DBF8ADD612F343EF9BFCA2FBA61BD4BF93E1E54626D227FDA812E18D071579AB4EEAC9901DAB183BCB0D9F48732D92CE66B386EAE5D8212C9FD156DC3F09B171B5603E17A468D244F3B6880EBCDA189BA9E23E4A4C6C2995ACF264F8CE9D54B27316343C0BC19221F75E6A2AC68011741695E599F73460B7A042E0461DB189CDCE223B40336BF2251AE3B363159960C9F63B47EFC43790D474DABB9A686DAF21E0DD76533749FCA9F144FA9C243CEF1364C79D981ED81DC4635C73B7F8908BA190AA920ED370F815BC2F9B3D28ED87BE34A01498836222C17B70C246C03CA1C111D2A227
diff --git a/openssh/mpaux.c b/openssh/mpaux.c
new file mode 100644 (file)
index 0000000..0c48627
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file contains various auxiliary functions related to multiple
+ * precision integers.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: mpaux.c,v 1.16 2001/02/08 19:30:52 itojun Exp $");
+
+#include <openssl/bn.h>
+#include "getput.h"
+#include "xmalloc.h"
+
+#include <openssl/md5.h>
+
+#include "mpaux.h"
+
+void
+compute_session_id(u_char session_id[16],
+    u_char cookie[8],
+    BIGNUM* host_key_n,
+    BIGNUM* session_key_n)
+{
+       u_int host_key_bytes = BN_num_bytes(host_key_n);
+       u_int session_key_bytes = BN_num_bytes(session_key_n);
+       u_int bytes = host_key_bytes + session_key_bytes;
+       u_char *buf = xmalloc(bytes);
+       MD5_CTX md;
+
+       BN_bn2bin(host_key_n, buf);
+       BN_bn2bin(session_key_n, buf + host_key_bytes);
+       MD5_Init(&md);
+       MD5_Update(&md, buf, bytes);
+       MD5_Update(&md, cookie, 8);
+       MD5_Final(session_id, &md);
+       memset(buf, 0, bytes);
+       xfree(buf);
+}
diff --git a/openssh/mpaux.h b/openssh/mpaux.h
new file mode 100644 (file)
index 0000000..082b7fd
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file contains various auxiliary functions related to multiple
+ * precision integers.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: mpaux.h,v 1.11 2001/06/26 17:27:24 markus Exp $"); */
+
+#ifndef MPAUX_H
+#define MPAUX_H
+
+void    compute_session_id(u_char[16], u_char[8], BIGNUM *, BIGNUM *);
+
+#endif                         /* MPAUX_H */
diff --git a/openssh/myproposal.h b/openssh/myproposal.h
new file mode 100644 (file)
index 0000000..4a9a363
--- /dev/null
@@ -0,0 +1,52 @@
+/*     $OpenBSD: myproposal.h,v 1.12 2001/03/05 15:56:16 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define KEX_DEFAULT_KEX                "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1"
+#define        KEX_DEFAULT_PK_ALG      "ssh-rsa,ssh-dss"
+#define        KEX_DEFAULT_ENCRYPT \
+       "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
+       "aes192-cbc,aes256-cbc," \
+       "rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \
+       "rijndael-cbc@lysator.liu.se"
+#define        KEX_DEFAULT_MAC \
+       "hmac-md5,hmac-sha1,hmac-ripemd160," \
+       "hmac-ripemd160@openssh.com," \
+       "hmac-sha1-96,hmac-md5-96"
+#define        KEX_DEFAULT_COMP        "none,zlib"
+#define        KEX_DEFAULT_LANG        ""
+
+
+static char *myproposal[PROPOSAL_MAX] = {
+       KEX_DEFAULT_KEX,
+       KEX_DEFAULT_PK_ALG,
+       KEX_DEFAULT_ENCRYPT,
+       KEX_DEFAULT_ENCRYPT,
+       KEX_DEFAULT_MAC,
+       KEX_DEFAULT_MAC,
+       KEX_DEFAULT_COMP,
+       KEX_DEFAULT_COMP,
+       KEX_DEFAULT_LANG,
+       KEX_DEFAULT_LANG
+};
diff --git a/openssh/nchan.c b/openssh/nchan.c
new file mode 100644 (file)
index 0000000..2680f0a
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: nchan.c,v 1.32 2001/10/10 22:18:47 markus Exp $");
+
+#include "ssh1.h"
+#include "ssh2.h"
+#include "buffer.h"
+#include "packet.h"
+#include "channels.h"
+#include "compat.h"
+#include "log.h"
+
+/*
+ * SSH Protocol 1.5 aka New Channel Protocol
+ * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
+ * Written by Markus Friedl in October 1999
+ *
+ * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
+ * tear down of channels:
+ *
+ * 1.3:        strict request-ack-protocol:
+ *     CLOSE   ->
+ *             <-  CLOSE_CONFIRM
+ *
+ * 1.5:        uses variations of:
+ *     IEOF    ->
+ *             <-  OCLOSE
+ *             <-  IEOF
+ *     OCLOSE  ->
+ *     i.e. both sides have to close the channel
+ *
+ * 2.0: the EOF messages are optional
+ *
+ * See the debugging output from 'ssh -v' and 'sshd -d' of
+ * ssh-1.2.27 as an example.
+ *
+ */
+
+/* functions manipulating channel states */
+/*
+ * EVENTS update channel input/output states execute ACTIONS
+ */
+/* events concerning the INPUT from socket for channel (istate) */
+chan_event_fn *chan_rcvd_oclose                        = NULL;
+chan_event_fn *chan_read_failed                        = NULL;
+chan_event_fn *chan_ibuf_empty                 = NULL;
+/* events concerning the OUTPUT from channel for socket (ostate) */
+chan_event_fn *chan_rcvd_ieof                  = NULL;
+chan_event_fn *chan_write_failed               = NULL;
+chan_event_fn *chan_obuf_empty                 = NULL;
+/*
+ * ACTIONS: should never update the channel states
+ */
+static void    chan_send_ieof1(Channel *);
+static void    chan_send_oclose1(Channel *);
+static void    chan_send_close2(Channel *);
+static void    chan_send_eof2(Channel *);
+
+/* helper */
+static void    chan_shutdown_write(Channel *);
+static void    chan_shutdown_read(Channel *);
+
+/*
+ * SSH1 specific implementation of event functions
+ */
+
+static void
+chan_rcvd_oclose1(Channel *c)
+{
+       debug("channel %d: rcvd oclose", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_WAIT_OCLOSE:
+               debug("channel %d: input wait_oclose -> closed", c->self);
+               c->istate = CHAN_INPUT_CLOSED;
+               break;
+       case CHAN_INPUT_OPEN:
+               debug("channel %d: input open -> closed", c->self);
+               chan_shutdown_read(c);
+               chan_send_ieof1(c);
+               c->istate = CHAN_INPUT_CLOSED;
+               break;
+       case CHAN_INPUT_WAIT_DRAIN:
+               /* both local read_failed and remote write_failed  */
+               log("channel %d: input drain -> closed", c->self);
+               chan_send_ieof1(c);
+               c->istate = CHAN_INPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: protocol error: rcvd_oclose for istate %d",
+                   c->self, c->istate);
+               return;
+       }
+}
+static void
+chan_read_failed_12(Channel *c)
+{
+       debug("channel %d: read failed", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+               debug("channel %d: input open -> drain", c->self);
+               chan_shutdown_read(c);
+               c->istate = CHAN_INPUT_WAIT_DRAIN;
+#if 0
+               if (buffer_len(&c->input) == 0) {
+                       debug("channel %d: input: no drain shortcut", c->self);
+                       chan_ibuf_empty(c);
+               }
+#endif
+               break;
+       default:
+               error("channel %d: chan_read_failed for istate %d",
+                   c->self, c->istate);
+               break;
+       }
+}
+static void
+chan_ibuf_empty1(Channel *c)
+{
+       debug("channel %d: ibuf empty", c->self);
+       if (buffer_len(&c->input)) {
+               error("channel %d: chan_ibuf_empty for non empty buffer",
+                   c->self);
+               return;
+       }
+       switch (c->istate) {
+       case CHAN_INPUT_WAIT_DRAIN:
+               debug("channel %d: input drain -> wait_oclose", c->self);
+               chan_send_ieof1(c);
+               c->istate = CHAN_INPUT_WAIT_OCLOSE;
+               break;
+       default:
+               error("channel %d: chan_ibuf_empty for istate %d",
+                   c->self, c->istate);
+               break;
+       }
+}
+static void
+chan_rcvd_ieof1(Channel *c)
+{
+       debug("channel %d: rcvd ieof", c->self);
+       if (c->type != SSH_CHANNEL_OPEN) {
+               debug("channel %d: non-open", c->self);
+               if (c->istate == CHAN_INPUT_OPEN) {
+                       debug("channel %d: non-open: input open -> wait_oclose",
+                           c->self);
+                       chan_shutdown_read(c);
+                       chan_send_ieof1(c);
+                       c->istate = CHAN_INPUT_WAIT_OCLOSE;
+               } else {
+                       error("channel %d: non-open: istate %d != open",
+                           c->self, c->istate);
+               }
+               if (c->ostate == CHAN_OUTPUT_OPEN) {
+                       debug("channel %d: non-open: output open -> closed",
+                           c->self);
+                       chan_send_oclose1(c);
+                       c->ostate = CHAN_OUTPUT_CLOSED;
+               } else {
+                       error("channel %d: non-open: ostate %d != open",
+                           c->self, c->ostate);
+               }
+               return;
+       }
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+               debug("channel %d: output open -> drain", c->self);
+               c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
+               break;
+       case CHAN_OUTPUT_WAIT_IEOF:
+               debug("channel %d: output wait_ieof -> closed", c->self);
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: protocol error: rcvd_ieof for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+static void
+chan_write_failed1(Channel *c)
+{
+       debug("channel %d: write failed", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+               debug("channel %d: output open -> wait_ieof", c->self);
+               chan_send_oclose1(c);
+               c->ostate = CHAN_OUTPUT_WAIT_IEOF;
+               break;
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               debug("channel %d: output wait_drain -> closed", c->self);
+               chan_send_oclose1(c);
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: chan_write_failed for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+static void
+chan_obuf_empty1(Channel *c)
+{
+       debug("channel %d: obuf empty", c->self);
+       if (buffer_len(&c->output)) {
+               error("channel %d: chan_obuf_empty for non empty buffer",
+                   c->self);
+               return;
+       }
+       switch (c->ostate) {
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               debug("channel %d: output drain -> closed", c->self);
+               chan_send_oclose1(c);
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: internal error: obuf_empty for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+static void
+chan_send_ieof1(Channel *c)
+{
+       debug("channel %d: send ieof", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+       case CHAN_INPUT_WAIT_DRAIN:
+               packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
+               packet_put_int(c->remote_id);
+               packet_send();
+               break;
+       default:
+               error("channel %d: cannot send ieof for istate %d",
+                   c->self, c->istate);
+               break;
+       }
+}
+static void
+chan_send_oclose1(Channel *c)
+{
+       debug("channel %d: send oclose", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               chan_shutdown_write(c);
+               buffer_consume(&c->output, buffer_len(&c->output));
+               packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
+               packet_put_int(c->remote_id);
+               packet_send();
+               break;
+       default:
+               error("channel %d: cannot send oclose for ostate %d",
+                    c->self, c->ostate);
+               break;
+       }
+}
+
+/*
+ * the same for SSH2
+ */
+static void
+chan_rcvd_oclose2(Channel *c)
+{
+       debug("channel %d: rcvd close", c->self);
+       if (c->flags & CHAN_CLOSE_RCVD)
+               error("channel %d: protocol error: close rcvd twice", c->self);
+       c->flags |= CHAN_CLOSE_RCVD;
+       if (c->type == SSH_CHANNEL_LARVAL) {
+               /* tear down larval channels immediately */
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               c->istate = CHAN_INPUT_CLOSED;
+               return;
+       }
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+               /*
+                * wait until a data from the channel is consumed if a CLOSE
+                * is received
+                */
+               debug("channel %d: output open -> drain", c->self);
+               c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
+               break;
+       }
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+               debug("channel %d: input open -> closed", c->self);
+               chan_shutdown_read(c);
+               break;
+       case CHAN_INPUT_WAIT_DRAIN:
+               debug("channel %d: input drain -> closed", c->self);
+               chan_send_eof2(c);
+               break;
+       }
+       c->istate = CHAN_INPUT_CLOSED;
+}
+static void
+chan_ibuf_empty2(Channel *c)
+{
+       debug("channel %d: ibuf empty", c->self);
+       if (buffer_len(&c->input)) {
+               error("channel %d: chan_ibuf_empty for non empty buffer",
+                    c->self);
+               return;
+       }
+       switch (c->istate) {
+       case CHAN_INPUT_WAIT_DRAIN:
+               debug("channel %d: input drain -> closed", c->self);
+               if (!(c->flags & CHAN_CLOSE_SENT))
+                       chan_send_eof2(c);
+               c->istate = CHAN_INPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: chan_ibuf_empty for istate %d",
+                    c->self, c->istate);
+               break;
+       }
+}
+static void
+chan_rcvd_ieof2(Channel *c)
+{
+       debug("channel %d: rcvd eof", c->self);
+       if (c->ostate == CHAN_OUTPUT_OPEN) {
+               debug("channel %d: output open -> drain", c->self);
+               c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
+       }
+}
+static void
+chan_write_failed2(Channel *c)
+{
+       debug("channel %d: write failed", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+               debug("channel %d: output open -> closed", c->self);
+               chan_shutdown_write(c); /* ?? */
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               break;
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               debug("channel %d: output drain -> closed", c->self);
+               chan_shutdown_write(c);
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: chan_write_failed for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+static void
+chan_obuf_empty2(Channel *c)
+{
+       debug("channel %d: obuf empty", c->self);
+       if (buffer_len(&c->output)) {
+               error("channel %d: chan_obuf_empty for non empty buffer",
+                   c->self);
+               return;
+       }
+       switch (c->ostate) {
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               debug("channel %d: output drain -> closed", c->self);
+               chan_shutdown_write(c);
+               c->ostate = CHAN_OUTPUT_CLOSED;
+               break;
+       default:
+               error("channel %d: chan_obuf_empty for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+static void
+chan_send_eof2(Channel *c)
+{
+       debug("channel %d: send eof", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_WAIT_DRAIN:
+               packet_start(SSH2_MSG_CHANNEL_EOF);
+               packet_put_int(c->remote_id);
+               packet_send();
+               break;
+       default:
+               error("channel %d: cannot send eof for istate %d",
+                   c->self, c->istate);
+               break;
+       }
+}
+static void
+chan_send_close2(Channel *c)
+{
+       debug("channel %d: send close", c->self);
+       if (c->ostate != CHAN_OUTPUT_CLOSED ||
+           c->istate != CHAN_INPUT_CLOSED) {
+               error("channel %d: cannot send close for istate/ostate %d/%d",
+                   c->self, c->istate, c->ostate);
+       } else if (c->flags & CHAN_CLOSE_SENT) {
+               error("channel %d: already sent close", c->self);
+       } else {
+               packet_start(SSH2_MSG_CHANNEL_CLOSE);
+               packet_put_int(c->remote_id);
+               packet_send();
+               c->flags |= CHAN_CLOSE_SENT;
+       }
+}
+
+/* shared */
+
+void
+chan_mark_dead(Channel *c)
+{
+       c->type = SSH_CHANNEL_ZOMBIE;
+}
+
+int
+chan_is_dead(Channel *c, int send)
+{
+       if (c->type == SSH_CHANNEL_ZOMBIE) {
+               debug("channel %d: zombie", c->self);
+               return 1;
+       }
+       if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
+               return 0;
+       if (!compat20) {
+               debug("channel %d: is dead", c->self);
+               return 1;
+       }
+       /*
+        * we have to delay the close message if the efd (for stderr) is
+        * still active
+        */
+       if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
+           buffer_len(&c->extended) > 0)
+#if 0
+           || ((c->extended_usage == CHAN_EXTENDED_READ) &&
+           c->efd != -1)
+#endif
+           ) {
+               debug2("channel %d: active efd: %d len %d type %s",
+                   c->self, c->efd, buffer_len(&c->extended),
+                   c->extended_usage==CHAN_EXTENDED_READ ?
+                      "read": "write");
+       } else {
+               if (!(c->flags & CHAN_CLOSE_SENT)) {
+                       if (send) {
+                               chan_send_close2(c);
+                       } else {
+                               /* channel would be dead if we sent a close */
+                               if (c->flags & CHAN_CLOSE_RCVD) {
+                                       debug("channel %d: almost dead",
+                                           c->self);
+                                       return 1;
+                               }
+                       }
+               }
+               if ((c->flags & CHAN_CLOSE_SENT) &&
+                   (c->flags & CHAN_CLOSE_RCVD)) {
+                       debug("channel %d: is dead", c->self);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+void
+chan_init_iostates(Channel *c)
+{
+       c->ostate = CHAN_OUTPUT_OPEN;
+       c->istate = CHAN_INPUT_OPEN;
+       c->flags = 0;
+}
+
+/* init */
+void
+chan_init(void)
+{
+       if (compat20) {
+               chan_rcvd_oclose                = chan_rcvd_oclose2;
+               chan_read_failed                = chan_read_failed_12;
+               chan_ibuf_empty                 = chan_ibuf_empty2;
+
+               chan_rcvd_ieof                  = chan_rcvd_ieof2;
+               chan_write_failed               = chan_write_failed2;
+               chan_obuf_empty                 = chan_obuf_empty2;
+       } else {
+               chan_rcvd_oclose                = chan_rcvd_oclose1;
+               chan_read_failed                = chan_read_failed_12;
+               chan_ibuf_empty                 = chan_ibuf_empty1;
+
+               chan_rcvd_ieof                  = chan_rcvd_ieof1;
+               chan_write_failed               = chan_write_failed1;
+               chan_obuf_empty                 = chan_obuf_empty1;
+       }
+}
+
+/* helper */
+static void
+chan_shutdown_write(Channel *c)
+{
+       buffer_consume(&c->output, buffer_len(&c->output));
+       if (compat20 && c->type == SSH_CHANNEL_LARVAL)
+               return;
+       /* shutdown failure is allowed if write failed already */
+       debug("channel %d: close_write", c->self);
+       if (c->sock != -1) {
+               if (shutdown(c->sock, SHUT_WR) < 0)
+                       debug("channel %d: chan_shutdown_write: "
+                           "shutdown() failed for fd%d: %.100s",
+                           c->self, c->sock, strerror(errno));
+       } else {
+               if (channel_close_fd(&c->wfd) < 0)
+                       log("channel %d: chan_shutdown_write: "
+                           "close() failed for fd%d: %.100s",
+                           c->self, c->wfd, strerror(errno));
+       }
+}
+static void
+chan_shutdown_read(Channel *c)
+{
+       if (compat20 && c->type == SSH_CHANNEL_LARVAL)
+               return;
+       debug("channel %d: close_read", c->self);
+       if (c->sock != -1) {
+               /*
+                * shutdown(sock, SHUT_READ) may return ENOTCONN if the
+                * write side has been closed already. (bug on Linux)
+                * HP-UX may return ENOTCONN also.
+                */
+               if (shutdown(c->sock, SHUT_RD) < 0
+                   && errno != ENOTCONN)
+                       error("channel %d: chan_shutdown_read: "
+                           "shutdown() failed for fd%d [i%d o%d]: %.100s",
+                           c->self, c->sock, c->istate, c->ostate,
+                           strerror(errno));
+       } else {
+               if (channel_close_fd(&c->rfd) < 0)
+                       log("channel %d: chan_shutdown_read: "
+                           "close() failed for fd%d: %.100s",
+                           c->self, c->rfd, strerror(errno));
+       }
+}
diff --git a/openssh/nchan.ms b/openssh/nchan.ms
new file mode 100644 (file)
index 0000000..2d08022
--- /dev/null
@@ -0,0 +1,99 @@
+.\"    $OpenBSD: nchan.ms,v 1.7 2001/01/29 01:58:17 niklas Exp $
+.\"
+.\" 
+.\" Copyright (c) 1999 Markus Friedl.  All rights reserved.
+.\" 
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.TL
+OpenSSH Channel Close Protocol 1.5 Implementation
+.SH
+Channel Input State Diagram
+.PS
+reset
+l=1
+s=1.2
+ellipsewid=s*ellipsewid
+boxwid=s*boxwid
+ellipseht=s*ellipseht
+S1: ellipse "INPUT" "OPEN"
+move right 2*l from last ellipse.e
+S4: ellipse "INPUT" "CLOSED"
+move down l from last ellipse.s
+S3: ellipse "INPUT" "WAIT" "OCLOSED"
+move down l from 1st ellipse.s
+S2: ellipse "INPUT" "WAIT" "DRAIN"
+arrow "" "rcvd OCLOSE/" "shutdown_read" "send IEOF" from S1.e to S4.w
+arrow "ibuf_empty/" "send IEOF" from S2.e to S3.w
+arrow from S1.s to S2.n
+box invis "read_failed/" "shutdown_read" with .e at last arrow.c
+arrow  from S3.n to S4.s
+box invis "rcvd OCLOSE/" "-" with .w at last arrow.c
+ellipse wid .9*ellipsewid ht .9*ellipseht at S4
+arrow "start" "" from S1.w+(-0.5,0) to S1.w
+arrow from S2.ne to S4.sw
+box invis "rcvd OCLOSE/     " with .e at last arrow.c
+box invis " send IEOF" with .w at last arrow.c
+.PE
+.SH
+Channel Output State Diagram
+.PS
+S1: ellipse "OUTPUT" "OPEN"
+move right 2*l from last ellipse.e
+S3: ellipse "OUTPUT" "WAIT" "IEOF"
+move down l from last ellipse.s
+S4: ellipse "OUTPUT" "CLOSED"
+move down l from 1st ellipse.s
+S2: ellipse "OUTPUT" "WAIT" "DRAIN"
+arrow "" "write_failed/" "shutdown_write" "send OCLOSE" from S1.e to S3.w
+arrow "obuf_empty ||" "write_failed/" "shutdown_write" "send OCLOSE" from S2.e to S4.w
+arrow from S1.s to S2.n
+box invis "rcvd IEOF/" "-" with .e at last arrow.c
+arrow from S3.s to S4.n
+box invis "rcvd IEOF/" "-" with .w at last arrow.c
+ellipse wid .9*ellipsewid ht .9*ellipseht at S4
+arrow "start" "" from S1.w+(-0.5,0) to S1.w
+.PE
+.SH
+Notes
+.PP
+The input buffer is filled with data from the socket
+(the socket represents the local consumer/producer of the
+forwarded channel).
+The data is then sent over the INPUT-end (transmit-end) of the channel to the
+remote peer.
+Data sent by the peer is received on the OUTPUT-end (receive-end),
+saved in the output buffer and written to the socket.
+.PP
+If the local protocol instance has forwarded all data on the
+INPUT-end of the channel, it sends an IEOF message to the peer.
+If the peer receives the IEOF and has consumed all
+data he replies with an OCLOSE.
+When the local instance receives the OCLOSE
+he considers the INPUT-half of the channel closed.
+The peer has his OUTOUT-half closed.
+.PP
+A channel can be deallocated by a protocol instance
+if both the INPUT- and the OUTOUT-half on his
+side of the channel are closed.
+Note that when an instance is unable to consume the
+received data, he is permitted to send an OCLOSE
+before the matching IEOF is received.
diff --git a/openssh/nchan2.ms b/openssh/nchan2.ms
new file mode 100644 (file)
index 0000000..1cc51fa
--- /dev/null
@@ -0,0 +1,88 @@
+.\"    $OpenBSD: nchan2.ms,v 1.2 2001/10/03 10:05:57 markus Exp $
+.\" 
+.\" Copyright (c) 2000 Markus Friedl.  All rights reserved.
+.\" 
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.TL
+OpenSSH Channel Close Protocol 2.0 Implementation
+.SH
+Channel Input State Diagram
+.PS
+reset
+l=1
+s=1.2
+ellipsewid=s*ellipsewid
+boxwid=s*boxwid
+ellipseht=s*ellipseht
+S1: ellipse "INPUT" "OPEN"
+move right 2*l from last ellipse.e
+S3: ellipse invis
+move down l from last ellipse.s
+S4: ellipse "INPUT" "CLOSED"
+move down l from 1st ellipse.s
+S2: ellipse "INPUT" "WAIT" "DRAIN"
+arrow from S1.e to S4.n
+box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c
+arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w
+arrow from S1.s to S2.n
+box invis "read_failed/" "shutdown_read" with .e at last arrow.c
+ellipse wid .9*ellipsewid ht .9*ellipseht at S4
+arrow "start" "" from S1.w+(-0.5,0) to S1.w
+.PE
+.SH
+Channel Output State Diagram
+.PS
+S1: ellipse "OUTPUT" "OPEN"
+move right 2*l from last ellipse.e
+S3: ellipse invis
+move down l from last ellipse.s
+S4: ellipse "OUTPUT" "CLOSED"
+move down l from 1st ellipse.s
+S2: ellipse "OUTPUT" "WAIT" "DRAIN"
+arrow from S1.e to S4.n
+box invis "write_failed/" "shutdown_write" with .sw at last arrow.c
+arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
+arrow from S1.s to S2.n
+box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c
+ellipse wid .9*ellipsewid ht .9*ellipseht at S4
+arrow "start" "" from S1.w+(-0.5,0) to S1.w
+.PE
+.SH
+Notes
+.PP
+The input buffer is filled with data from the socket
+(the socket represents the local consumer/producer of the
+forwarded channel).
+The data is then sent over the INPUT-end (transmit-end) of the channel to the
+remote peer.
+Data sent by the peer is received on the OUTPUT-end (receive-end),
+saved in the output buffer and written to the socket.
+.PP
+If the local protocol instance has forwarded all data on the
+INPUT-end of the channel, it sends an EOF message to the peer.
+.PP
+A CLOSE message is sent to the peer if
+both the INPUT- and the OUTOUT-half of the local
+end of the channel are closed.
+.PP
+The channel can be deallocated by a protocol instance
+if a CLOSE message he been both sent and received.
diff --git a/openssh/openbsd-compat/.cvsignore b/openssh/openbsd-compat/.cvsignore
new file mode 100644 (file)
index 0000000..f3c7a7c
--- /dev/null
@@ -0,0 +1 @@
+Makefile
diff --git a/openssh/openbsd-compat/Makefile.in b/openssh/openbsd-compat/Makefile.in
new file mode 100644 (file)
index 0000000..31f9ea9
--- /dev/null
@@ -0,0 +1,39 @@
+# $Id$
+
+sysconfdir=@sysconfdir@
+piddir=@piddir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+
+VPATH=@srcdir@
+CC=@CC@
+LD=@LD@
+CFLAGS=@CFLAGS@
+CPPFLAGS=-I. -I.. -I$(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@
+LIBS=@LIBS@
+AR=@AR@
+RANLIB=@RANLIB@
+INSTALL=@INSTALL@
+LDFLAGS=-L. @LDFLAGS@
+
+OPENBSD=base64.o bindresvport.o daemon.o dirname.o getcwd.o getgrouplist.o getopt.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sigact.o strlcat.o strlcpy.o strmode.o strsep.o
+
+COMPAT=bsd-arc4random.o bsd-cray.o bsd-cygwin_util.o bsd-misc.o bsd-nextstep.o bsd-snprintf.o bsd-waitpid.o fake-getaddrinfo.o fake-getnameinfo.o
+
+.c.o:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+
+all: libopenbsd-compat.a
+
+$(COMPAT): ../config.h
+$(OPENBSD): ../config.h
+
+libopenbsd-compat.a:  $(COMPAT) $(OPENBSD)
+       $(AR) rv $@ $(COMPAT) $(OPENBSD)
+       $(RANLIB) $@
+
+clean:
+       rm -f *.o *.a core 
+
+distclean: clean
+       rm -f Makefile *~
diff --git a/openssh/openbsd-compat/base64.c b/openssh/openbsd-compat/base64.c
new file mode 100644 (file)
index 0000000..d12b993
--- /dev/null
@@ -0,0 +1,316 @@
+/*     $OpenBSD: base64.c,v 1.3 1997/11/08 20:46:55 deraadt Exp $      */
+
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include "config.h"
+
+#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base64.h"
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+   The following encoding technique is taken from RFC 1521 by Borenstein
+   and Freed.  It is reproduced here in a slightly edited form for
+   convenience.
+
+   A 65-character subset of US-ASCII is used, enabling 6 bits to be
+   represented per printable character. (The extra 65th character, "=",
+   is used to signify a special processing function.)
+
+   The encoding process represents 24-bit groups of input bits as output
+   strings of 4 encoded characters. Proceeding from left to right, a
+   24-bit input group is formed by concatenating 3 8-bit input groups.
+   These 24 bits are then treated as 4 concatenated 6-bit groups, each
+   of which is translated into a single digit in the base64 alphabet.
+
+   Each 6-bit group is used as an index into an array of 64 printable
+   characters. The character referenced by the index is placed in the
+   output string.
+
+                         Table 1: The Base64 Alphabet
+
+      Value Encoding  Value Encoding  Value Encoding  Value Encoding
+          0 A            17 R            34 i            51 z
+          1 B            18 S            35 j            52 0
+          2 C            19 T            36 k            53 1
+          3 D            20 U            37 l            54 2
+          4 E            21 V            38 m            55 3
+          5 F            22 W            39 n            56 4
+          6 G            23 X            40 o            57 5
+          7 H            24 Y            41 p            58 6
+          8 I            25 Z            42 q            59 7
+          9 J            26 a            43 r            60 8
+         10 K            27 b            44 s            61 9
+         11 L            28 c            45 t            62 +
+         12 M            29 d            46 u            63 /
+         13 N            30 e            47 v
+         14 O            31 f            48 w         (pad) =
+         15 P            32 g            49 x
+         16 Q            33 h            50 y
+
+   Special processing is performed if fewer than 24 bits are available
+   at the end of the data being encoded.  A full encoding quantum is
+   always completed at the end of a quantity.  When fewer than 24 input
+   bits are available in an input group, zero bits are added (on the
+   right) to form an integral number of 6-bit groups.  Padding at the
+   end of the data is performed using the '=' character.
+
+   Since all base64 input is an integral number of octets, only the
+         -------------------------------------------------                       
+   following cases can arise:
+   
+       (1) the final quantum of encoding input is an integral
+           multiple of 24 bits; here, the final unit of encoded
+          output will be an integral multiple of 4 characters
+          with no "=" padding,
+       (2) the final quantum of encoding input is exactly 8 bits;
+           here, the final unit of encoded output will be two
+          characters followed by two "=" padding characters, or
+       (3) the final quantum of encoding input is exactly 16 bits;
+           here, the final unit of encoded output will be three
+          characters followed by one "=" padding character.
+   */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize)
+{
+       size_t datalength = 0;
+       u_char input[3];
+       u_char output[4];
+       int i;
+
+       while (2 < srclength) {
+               input[0] = *src++;
+               input[1] = *src++;
+               input[2] = *src++;
+               srclength -= 3;
+
+               output[0] = input[0] >> 2;
+               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+               output[3] = input[2] & 0x3f;
+               Assert(output[0] < 64);
+               Assert(output[1] < 64);
+               Assert(output[2] < 64);
+               Assert(output[3] < 64);
+
+               if (datalength + 4 > targsize)
+                       return (-1);
+               target[datalength++] = Base64[output[0]];
+               target[datalength++] = Base64[output[1]];
+               target[datalength++] = Base64[output[2]];
+               target[datalength++] = Base64[output[3]];
+       }
+    
+       /* Now we worry about padding. */
+       if (0 != srclength) {
+               /* Get what's left. */
+               input[0] = input[1] = input[2] = '\0';
+               for (i = 0; i < srclength; i++)
+                       input[i] = *src++;
+       
+               output[0] = input[0] >> 2;
+               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+               Assert(output[0] < 64);
+               Assert(output[1] < 64);
+               Assert(output[2] < 64);
+
+               if (datalength + 4 > targsize)
+                       return (-1);
+               target[datalength++] = Base64[output[0]];
+               target[datalength++] = Base64[output[1]];
+               if (srclength == 1)
+                       target[datalength++] = Pad64;
+               else
+                       target[datalength++] = Base64[output[2]];
+               target[datalength++] = Pad64;
+       }
+       if (datalength >= targsize)
+               return (-1);
+       target[datalength] = '\0';      /* Returned value doesn't count \0. */
+       return (datalength);
+}
+
+/* skips all whitespace anywhere.
+   converts characters, four at a time, starting at (or after)
+   src from base - 64 numbers into three 8 bit bytes in the target area.
+   it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(char const *src, u_char *target, size_t targsize)
+{
+       int tarindex, state, ch;
+       char *pos;
+
+       state = 0;
+       tarindex = 0;
+
+       while ((ch = *src++) != '\0') {
+               if (isspace(ch))        /* Skip whitespace anywhere. */
+                       continue;
+
+               if (ch == Pad64)
+                       break;
+
+               pos = strchr(Base64, ch);
+               if (pos == 0)           /* A non-base64 character. */
+                       return (-1);
+
+               switch (state) {
+               case 0:
+                       if (target) {
+                               if (tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] = (pos - Base64) << 2;
+                       }
+                       state = 1;
+                       break;
+               case 1:
+                       if (target) {
+                               if (tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 4;
+                               target[tarindex+1]  = ((pos - Base64) & 0x0f)
+                                                       << 4 ;
+                       }
+                       tarindex++;
+                       state = 2;
+                       break;
+               case 2:
+                       if (target) {
+                               if (tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 2;
+                               target[tarindex+1]  = ((pos - Base64) & 0x03)
+                                                       << 6;
+                       }
+                       tarindex++;
+                       state = 3;
+                       break;
+               case 3:
+                       if (target) {
+                               if (tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] |= (pos - Base64);
+                       }
+                       tarindex++;
+                       state = 0;
+                       break;
+               }
+       }
+
+       /*
+        * We are done decoding Base-64 chars.  Let's see if we ended
+        * on a byte boundary, and/or with erroneous trailing characters.
+        */
+
+       if (ch == Pad64) {              /* We got a pad char. */
+               ch = *src++;            /* Skip it, get next. */
+               switch (state) {
+               case 0:         /* Invalid = in first position */
+               case 1:         /* Invalid = in second position */
+                       return (-1);
+
+               case 2:         /* Valid, means one byte of info */
+                       /* Skip any number of spaces. */
+                       for (; ch != '\0'; ch = *src++)
+                               if (!isspace(ch))
+                                       break;
+                       /* Make sure there is another trailing = sign. */
+                       if (ch != Pad64)
+                               return (-1);
+                       ch = *src++;            /* Skip the = */
+                       /* Fall through to "single trailing =" case. */
+                       /* FALLTHROUGH */
+
+               case 3:         /* Valid, means two bytes of info */
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for (; ch != '\0'; ch = *src++)
+                               if (!isspace(ch))
+                                       return (-1);
+
+                       /*
+                        * Now make sure for cases 2 and 3 that the "extra"
+                        * bits that slopped past the last full byte were
+                        * zeros.  If we don't check them, they become a
+                        * subliminal channel.
+                        */
+                       if (target && target[tarindex] != 0)
+                               return (-1);
+               }
+       } else {
+               /*
+                * We ended by seeing the end of the string.  Make sure we
+                * have no partial bytes lying around.
+                */
+               if (state != 0)
+                       return (-1);
+       }
+
+       return (tarindex);
+}
+
+#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */
diff --git a/openssh/openbsd-compat/base64.h b/openssh/openbsd-compat/base64.h
new file mode 100644 (file)
index 0000000..0ebfdd3
--- /dev/null
@@ -0,0 +1,18 @@
+/* $Id$ */
+
+#ifndef _BSD_BASE64_H
+#define _BSD_BASE64_H
+
+#include "config.h"
+
+#ifndef HAVE___B64_NTOP
+# ifndef HAVE_B64_NTOP
+int b64_ntop(u_char const *src, size_t srclength, char *target, 
+    size_t targsize);
+int b64_pton(char const *src, u_char *target, size_t targsize);
+# endif /* !HAVE_B64_NTOP */
+# define __b64_ntop b64_ntop
+# define __b64_pton b64_pton
+#endif /* HAVE___B64_NTOP */
+
+#endif /* _BSD_BINRESVPORT_H */
diff --git a/openssh/openbsd-compat/bindresvport.c b/openssh/openbsd-compat/bindresvport.c
new file mode 100644 (file)
index 0000000..332bcb0
--- /dev/null
@@ -0,0 +1,123 @@
+/* This file has be modified from the original OpenBSD source */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#include "config.h"
+
+#ifndef HAVE_BINDRESVPORT_SA
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: bindresvport.c,v 1.13 2000/01/26 03:43:21 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ *
+ * Portions Copyright(C) 1996, Jason Downs.  All rights reserved.
+ */
+
+#include "includes.h"
+
+#define STARTPORT 600
+#define ENDPORT (IPPORT_RESERVED - 1)
+#define NPORTS (ENDPORT - STARTPORT + 1)
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport_sa(sd, sa)
+       int sd;
+       struct sockaddr *sa;
+{
+       int error, af;
+       struct sockaddr_storage myaddr;
+       struct sockaddr_in *sin;
+       struct sockaddr_in6 *sin6;
+       u_int16_t *portp;
+       u_int16_t port;
+       socklen_t salen;
+       int i;
+
+       if (sa == NULL) {
+               memset(&myaddr, 0, sizeof(myaddr));
+               sa = (struct sockaddr *)&myaddr;
+
+               if (getsockname(sd, sa, &salen) == -1)
+                       return -1;      /* errno is correctly set */
+
+               af = sa->sa_family;
+               memset(&myaddr, 0, salen);
+       } else
+               af = sa->sa_family;
+
+       if (af == AF_INET) {
+               sin = (struct sockaddr_in *)sa;
+               salen = sizeof(struct sockaddr_in);
+               portp = &sin->sin_port;
+       } else if (af == AF_INET6) {
+               sin6 = (struct sockaddr_in6 *)sa;
+               salen = sizeof(struct sockaddr_in6);
+               portp = &sin6->sin6_port;
+       } else {
+               errno = EPFNOSUPPORT;
+               return (-1);
+       }
+       sa->sa_family = af;
+
+       port = ntohs(*portp);
+       if (port == 0)
+               port = (arc4random() % NPORTS) + STARTPORT;
+
+       /* Avoid warning */
+       error = -1;
+
+       for(i = 0; i < NPORTS; i++) {
+               *portp = htons(port);
+               
+               error = bind(sd, sa, salen);
+
+               /* Terminate on success */
+               if (error == 0)
+                       break;
+                       
+               /* Terminate on errors, except "address already in use" */
+               if ((error < 0) && !((errno == EADDRINUSE) || (errno == EINVAL)))
+                       break;
+                       
+               port++;
+               if (port > ENDPORT)
+                       port = STARTPORT;
+       }
+
+       return (error);
+}
+
+#endif /* HAVE_BINDRESVPORT_SA */
diff --git a/openssh/openbsd-compat/bindresvport.h b/openssh/openbsd-compat/bindresvport.h
new file mode 100644 (file)
index 0000000..b56afd3
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_BINDRESVPORT_H
+#define _BSD_BINDRESVPORT_H
+
+#include "config.h"
+
+#ifndef HAVE_BINDRESVPORT_SA
+int bindresvport_sa(int sd, struct sockaddr *sa);
+#endif /* !HAVE_BINDRESVPORT_SA */
+
+#endif /* _BSD_BINDRESVPORT_H */
diff --git a/openssh/openbsd-compat/bsd-arc4random.c b/openssh/openbsd-compat/bsd-arc4random.c
new file mode 100644 (file)
index 0000000..4fcfc6e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1999-2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#include "log.h"
+
+RCSID("$Id$");
+
+#ifndef HAVE_ARC4RANDOM
+
+#include <openssl/rand.h>
+#include <openssl/rc4.h>
+#include <openssl/err.h>
+
+/* Size of key to use */
+#define SEED_SIZE 20
+
+/* Number of bytes to reseed after */
+#define REKEY_BYTES    (1 << 24)
+
+static int rc4_ready = 0;
+static RC4_KEY rc4;
+
+unsigned int arc4random(void)
+{
+       unsigned int r = 0;
+       static int first_time = 1;
+
+       if (rc4_ready <= 0) {
+               if (!first_time)
+                       seed_rng();
+               first_time = 0;
+               arc4random_stir();
+       }
+
+       RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
+
+       rc4_ready -= sizeof(r);
+       
+       return(r);
+}
+
+void arc4random_stir(void)
+{
+       unsigned char rand_buf[SEED_SIZE];
+
+       memset(&rc4, 0, sizeof(rc4));
+       if (!RAND_bytes(rand_buf, sizeof(rand_buf)))
+               fatal("Couldn't obtain random bytes (error %ld)",
+                   ERR_get_error());
+       RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
+       memset(rand_buf, 0, sizeof(rand_buf));
+
+       rc4_ready = REKEY_BYTES;
+}
+#endif /* !HAVE_ARC4RANDOM */
diff --git a/openssh/openbsd-compat/bsd-arc4random.h b/openssh/openbsd-compat/bsd-arc4random.h
new file mode 100644 (file)
index 0000000..3e913c3
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1999-2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _BSD_ARC4RANDOM_H
+#define _BSD_ARC4RANDOM_H
+
+#include "config.h"
+
+#ifndef HAVE_ARC4RANDOM
+unsigned int arc4random(void);
+void arc4random_stir(void);
+#endif /* !HAVE_ARC4RANDOM */
+
+#endif /* _BSD_ARC4RANDOM_H */
diff --git a/openssh/openbsd-compat/bsd-cray.c b/openssh/openbsd-compat/bsd-cray.c
new file mode 100644 (file)
index 0000000..fa76641
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * XXX: license?
+ */
+
+/*
+ * The modules contains code to support cray t3e and sv1 computers.
+ * It is here to minimize the modifcations to the openssh base code.
+ */
+
+#ifdef _CRAY
+
+#include <udb.h>
+#include <tmpdir.h>
+#include <unistd.h>
+#include <sys/category.h>
+#include <utmp.h>
+#include <sys/jtab.h>
+#include <signal.h>
+#include <sys/priv.h>
+#include <sys/secparm.h>
+#include <sys/usrv.h>
+#include <sys/sysv.h>
+#include <sys/sectab.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "bsd-cray.h"
+
+char cray_tmpdir[TPATHSIZ+1];              /* job TMPDIR path */
+
+/*
+ * Functions.
+ */
+void cray_retain_utmp(struct utmp *, int);
+void cray_delete_tmpdir(char *, int, uid_t);
+void cray_init_job(struct passwd *);
+void cray_set_tmpdir(struct utmp *);
+
+
+/*
+ * Orignal written by:
+ *     Wayne Schroeder
+ *     San Diego Supercomputer Center
+ *     schroeder@sdsc.edu
+*/
+void
+cray_setup(uid_t uid, char *username)
+{
+       struct udb *p;
+       extern char *setlimits();
+       int i, j;
+       int accts[MAXVIDS];
+       int naccts;
+       int err;
+       char *sr;
+       int pid;
+       struct jtab jbuf;
+       int jid;
+
+       if ((jid = getjtab(&jbuf)) < 0)
+               fatal("getjtab: no jid");
+
+       err = setudb();    /* open and rewind the Cray User DataBase */
+       if (err != 0)
+               fatal("UDB open failure");
+       naccts = 0;
+       p = getudbnam(username);
+       if (p == NULL)
+               fatal("No UDB entry for %.100s", username);
+       if (uid != p->ue_uid)
+               fatal("UDB entry %.100s uid(%d) does not match uid %d",
+                   username, (int) p->ue_uid, (int) uid);
+       for (j = 0; p->ue_acids[j] != -1 && j < MAXVIDS; j++) {
+               accts[naccts] = p->ue_acids[j];
+               naccts++;
+       }
+       endudb();        /* close the udb */
+
+       if (naccts != 0) {
+               /* Perhaps someday we'll prompt users who have multiple accounts
+                  to let them pick one (like CRI's login does), but for now just set
+                  the account to the first entry. */
+               if (acctid(0, accts[0]) < 0)
+                       fatal("System call acctid failed, accts[0]=%d", accts[0]);
+       }
+
+       /* Now set limits, including CPU time for the (interactive) job and process,
+          and set up permissions (for chown etc), etc.  This is via an internal CRI
+          routine, setlimits, used by CRI's login. */
+
+       pid = getpid();
+       sr = setlimits(username, C_PROC, pid, UDBRC_INTER);
+       if (sr != NULL)
+               fatal("%.200s", sr);
+
+       sr = setlimits(username, C_JOB, jid, UDBRC_INTER);
+       if (sr != NULL)
+               fatal("%.200s", sr);
+
+}
+
+/*
+ * The rc.* and /etc/sdaemon methods of starting a program on unicos/unicosmk
+ * can have pal privileges that sshd can inherit which
+ * could allow a user to su to root with out a password.
+ * This subroutine clears all privileges.
+ */
+void
+drop_cray_privs()
+{
+#if defined(_SC_CRAY_PRIV_SU)
+       priv_proc_t*              privstate;
+       int                       result;
+       extern      int           priv_set_proc();
+       extern      priv_proc_t*  priv_init_proc();
+       struct      usrv          usrv;
+
+       /*
+        * If ether of theses two flags are not set
+        * then don't allow this version of ssh to run.
+        */
+       if (!sysconf(_SC_CRAY_PRIV_SU))
+               fatal("Not PRIV_SU system.");
+       if (!sysconf(_SC_CRAY_POSIX_PRIV))
+               fatal("Not POSIX_PRIV.");
+
+       debug("Dropping privileges.");
+
+       memset(&usrv, 0, sizeof(usrv));
+       if (setusrv(&usrv) < 0)
+               fatal("%s(%d): setusrv(): %s", __FILE__, __LINE__,
+                   strerror(errno));
+
+       if ((privstate = priv_init_proc()) != NULL) {
+               result = priv_set_proc(privstate);
+               if (result != 0 )
+                       fatal("%s(%d): priv_set_proc(): %s",
+                           __FILE__, __LINE__, strerror(errno));
+               priv_free_proc(privstate);
+       }
+       debug ("Privileges should be cleared...");
+#else
+       /* XXX: do this differently */
+#      error Cray systems must be run with _SC_CRAY_PRIV_SU on!
+#endif
+}
+
+
+/*
+ *  Retain utmp/wtmp information - used by cray accounting.
+ */
+void
+cray_retain_utmp(struct utmp *ut, int pid)
+{
+       int fd;
+       struct utmp utmp;
+
+       if ((fd = open(UTMP_FILE, O_RDONLY)) != -1) {
+               while (read(fd, (char *)&utmp, sizeof(utmp)) == sizeof(utmp)) {
+                       if (pid == utmp.ut_pid) {
+                               ut->ut_jid = utmp.ut_jid;
+                               /* XXX: MIN_SIZEOF here? can this go in loginrec? */
+                               strncpy(ut->ut_tpath, utmp.ut_tpath, sizeof(utmp.ut_tpath));
+                               strncpy(ut->ut_host, utmp.ut_host, sizeof(utmp.ut_host));
+                               strncpy(ut->ut_name, utmp.ut_name, sizeof(utmp.ut_name));
+                               break;
+                       }
+               }
+               close(fd);
+       }
+       /* XXX: error message? */
+}
+
+/*
+ * tmpdir support.
+ */
+
+/*
+ * find and delete jobs tmpdir.
+ */
+void
+cray_delete_tmpdir(char *login, int jid, uid_t uid)
+{
+       int child;
+       static char jtmp[TPATHSIZ];
+       struct stat statbuf;
+       int c;
+       int wstat;
+
+       for (c = 'a'; c <= 'z'; c++) {
+               snprintf(jtmp, TPATHSIZ, "%s/jtmp.%06d%c", JTMPDIR, jid, c);
+               if (stat(jtmp, &statbuf) == 0 && statbuf.st_uid == uid)
+                       break;
+       }
+
+       if (c > 'z')
+               return;
+
+       if ((child = fork()) == 0) {
+               execl(CLEANTMPCMD, CLEANTMPCMD, login, jtmp, (char *)NULL);
+               fatal("cray_delete_tmpdir: execl of CLEANTMPCMD failed");
+       }
+
+       while (waitpid(child, &wstat, 0) == -1 && errno == EINTR)
+               ;
+}
+
+/*
+ * Remove tmpdir on job termination.
+ */
+void
+cray_job_termination_handler(int sig)
+{
+       int jid;
+       char *login = NULL;
+       struct jtab jtab;
+
+       debug("Received SIG JOB.");
+
+       if ((jid = waitjob(&jtab)) == -1 ||
+           (login = uid2nam(jtab.j_uid)) == NULL)
+               return;
+
+       cray_delete_tmpdir(login, jid, jtab.j_uid);
+}
+
+/*
+ * Set job id and create tmpdir directory.
+ */
+void
+cray_init_job(struct passwd *pw)
+{
+       int jid;
+       int c;
+
+       jid = setjob(pw->pw_uid, WJSIGNAL);
+       if (jid < 0)
+               fatal("System call setjob failure");
+
+       for (c = 'a'; c <= 'z'; c++) {
+               snprintf(cray_tmpdir, TPATHSIZ, "%s/jtmp.%06d%c", JTMPDIR, jid, c);
+               if (mkdir(cray_tmpdir, JTMPMODE) != 0)
+                       continue;
+               if (chown(cray_tmpdir,  pw->pw_uid, pw->pw_gid) != 0) {
+                       rmdir(cray_tmpdir);
+                       continue;
+               }
+               break;
+       }
+
+       if (c > 'z')
+               cray_tmpdir[0] = '\0';
+}
+
+void
+cray_set_tmpdir(struct utmp *ut)
+{
+       int jid;
+       struct jtab jbuf;
+
+       if ((jid = getjtab(&jbuf)) < 0)
+               return;
+
+       /*
+        * Set jid and tmpdir in utmp record.
+        */
+       ut->ut_jid = jid;
+       strncpy(ut->ut_tpath, cray_tmpdir, TPATHSIZ);
+}
+#endif
diff --git a/openssh/openbsd-compat/bsd-cray.h b/openssh/openbsd-compat/bsd-cray.h
new file mode 100644 (file)
index 0000000..ef36652
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _BSD_CRAY_H
+#define _BSD_CRAY_H
+
+#ifdef _CRAY
+void   cray_init_job(struct passwd *);         /* init cray job */
+void   cray_job_termination_handler(int);      /* process end of job signal */
+void   cray_setup(uid_t, char *);              /* set cray limits */
+extern char   cray_tmpdir[];                   /* cray tmpdir */
+#endif
+
+#endif /* _BSD_CRAY_H */
diff --git a/openssh/openbsd-compat/bsd-cygwin_util.c b/openssh/openbsd-compat/bsd-cygwin_util.c
new file mode 100644 (file)
index 0000000..f513331
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *
+ * cygwin_util.c
+ *
+ * Author: Corinna Vinschen <vinschen@cygnus.com>
+ *
+ * Copyright (c) 2000 Corinna Vinschen <vinschen@cygnus.com>, Duisburg, Germany
+ *                    All rights reserved
+ *
+ * Created: Sat Sep 02 12:17:00 2000 cv
+ *
+ * This file contains functions for forcing opened file descriptors to
+ * binary mode on Windows systems.
+ */
+
+#include "includes.h"
+
+RCSID("$Id$");
+
+#ifdef HAVE_CYGWIN
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <windows.h>
+#define is_winnt       (GetVersion() < 0x80000000)
+
+#define ntsec_on(c)    ((c) && strstr((c),"ntsec") && !strstr((c),"nontsec"))
+#define ntea_on(c)     ((c) && strstr((c),"ntea") && !strstr((c),"nontea"))
+
+#if defined(open) && open == binary_open
+# undef open
+#endif
+#if defined(pipe) && open == binary_pipe
+# undef pipe
+#endif
+
+int binary_open(const char *filename, int flags, ...)
+{
+       va_list ap;
+       mode_t mode;
+       
+       va_start(ap, flags);
+       mode = va_arg(ap, mode_t);
+       va_end(ap);
+       return open(filename, flags | O_BINARY, mode);
+}
+
+int binary_pipe(int fd[2])
+{
+       int ret = pipe(fd);
+
+       if (!ret) {
+               setmode (fd[0], O_BINARY);
+               setmode (fd[1], O_BINARY);
+       }
+       return ret;
+}
+
+int check_nt_auth(int pwd_authenticated, uid_t uid)
+{
+       /*
+       * The only authentication which is able to change the user
+       * context on NT systems is the password authentication. So
+       * we deny all requsts for changing the user context if another
+       * authentication method is used.
+       *
+       * This doesn't apply to Cygwin versions >= 1.3.2 anymore which
+       * uses the undocumented NtCreateToken() call to create a user
+       * token if the process has the appropriate privileges and if
+       * CYGWIN ntsec setting is on.
+       */
+       static int has_create_token = -1;
+
+       if (is_winnt) {
+               if (has_create_token < 0) {
+                       struct utsname uts;
+                       int major_high = 0, major_low = 0, minor = 0;
+                       char *cygwin = getenv("CYGWIN");
+
+                       has_create_token = 0;
+                       if (ntsec_on(cygwin) && !uname(&uts)) {
+                               sscanf(uts.release, "%d.%d.%d",
+                                      &major_high, &major_low, &minor);
+                               if (major_high > 1 ||
+                                   (major_high == 1 && (major_low > 3 ||
+                                    (major_low == 3 && minor >= 2))))
+                                       has_create_token = 1;
+                       }
+               }
+               if (has_create_token < 1 &&
+                   !pwd_authenticated && geteuid() != uid)
+                       return 0;
+       }
+       return 1;
+}
+
+int check_ntsec(const char *filename)
+{
+       char *cygwin;
+       int allow_ntea = 0;
+       int allow_ntsec = 0;
+       struct statfs fsstat;
+
+       /* Windows 95/98/ME don't support file system security at all. */
+       if (!is_winnt)
+               return 0;
+
+       /* Evaluate current CYGWIN settings. */
+       cygwin = getenv("CYGWIN");
+       allow_ntea = ntea_on(cygwin);
+       allow_ntsec = ntsec_on(cygwin);
+
+       /*
+        * `ntea' is an emulation of POSIX attributes. It doesn't support
+        * real file level security as ntsec on NTFS file systems does
+        * but it supports FAT filesystems. `ntea' is minimum requirement
+        * for security checks.
+        */
+       if (allow_ntea)
+               return 1;
+
+       /*
+        * Retrieve file system flags. In Cygwin, file system flags are
+        * copied to f_type which has no meaning in Win32 itself.
+        */
+       if (statfs(filename, &fsstat))
+               return 1;
+
+       /*
+        * Only file systems supporting ACLs are able to set permissions.
+        * `ntsec' is the setting in Cygwin which switches using of NTFS
+        * ACLs to support POSIX permissions on files.
+        */
+       if (fsstat.f_type & FS_PERSISTENT_ACLS)
+               return allow_ntsec;
+
+       return 0;
+}
+
+#endif /* HAVE_CYGWIN */
diff --git a/openssh/openbsd-compat/bsd-cygwin_util.h b/openssh/openbsd-compat/bsd-cygwin_util.h
new file mode 100644 (file)
index 0000000..8bd5fad
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *
+ * cygwin_util.c
+ *
+ * Author: Corinna Vinschen <vinschen@cygnus.com>
+ *
+ * Copyright (c) 2000 Corinna Vinschen <vinschen@cygnus.com>, Duisburg, Germany
+ *                    All rights reserved
+ *
+ * Created: Sat Sep 02 12:17:00 2000 cv
+ *
+ * This file contains functions for forcing opened file descriptors to
+ * binary mode on Windows systems.
+ */
+
+/* $Id$ */
+
+#ifndef _BSD_CYGWIN_UTIL_H
+#define _BSD_CYGWIN_UTIL_H
+
+#ifdef HAVE_CYGWIN
+
+#include <io.h>
+
+int binary_open(const char *filename, int flags, ...);
+int binary_pipe(int fd[2]);
+int check_nt_auth(int pwd_authenticated, uid_t uid);
+int check_ntsec(const char *filename);
+
+#define open binary_open
+#define pipe binary_pipe
+
+#endif /* HAVE_CYGWIN */
+
+#endif /* _BSD_CYGWIN_UTIL_H */
diff --git a/openssh/openbsd-compat/bsd-misc.c b/openssh/openbsd-compat/bsd-misc.c
new file mode 100644 (file)
index 0000000..d87d562
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1999-2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+RCSID("$Id$");
+
+char *get_progname(char *argv0)
+{
+#ifdef HAVE___PROGNAME
+       extern char *__progname;
+
+       return __progname;
+#else
+       char *p;
+
+       if (argv0 == NULL)
+               return "unknown";       /* XXX */
+       p = strrchr(argv0, '/');
+       if (p == NULL)
+               p = argv0;
+       else
+               p++;
+       return p;
+#endif
+}
+
+#ifndef HAVE_SETLOGIN
+int setlogin(const char *name)
+{
+       return(0);
+}
+#endif /* !HAVE_SETLOGIN */
+
+#ifndef HAVE_INNETGR
+int innetgr(const char *netgroup, const char *host, 
+            const char *user, const char *domain)
+{
+       return(0);
+}
+#endif /* HAVE_INNETGR */
+
+#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
+int seteuid(uid_t euid)
+{
+       return(setreuid(-1,euid));
+}
+#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */
+
+#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
+int setegid(uid_t egid)
+{
+       return(setresgid(-1,egid,-1));
+}
+#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
+
+#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR)
+const char *strerror(int e)
+{
+       extern int sys_nerr;
+       extern char *sys_errlist[];
+       
+       if ((e >= 0) && (e < sys_nerr))
+               return(sys_errlist[e]);
+       else
+               return("unlisted error");
+}
+#endif
+
+#ifndef HAVE_UTIMES
+int utimes(char *filename, struct timeval *tvp)
+{
+       struct utimbuf ub;
+
+       ub.actime = tvp->tv_sec;
+       ub.modtime = tvp->tv_usec;
+       
+       return(utime(filename, &ub));
+}
+#endif 
diff --git a/openssh/openbsd-compat/bsd-misc.h b/openssh/openbsd-compat/bsd-misc.h
new file mode 100644 (file)
index 0000000..3a85526
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1999-2000 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _BSD_MISC_H
+#define _BSD_MISC_H
+
+#include "config.h"
+
+char *get_progname(char *argv0);
+
+#ifndef HAVE_SETSID
+#define setsid() setpgrp(0, getpid())
+#endif /* !HAVE_SETSID */
+
+#ifndef HAVE_SETENV
+int setenv(const char *name, const char *value, int overwrite);
+#endif /* !HAVE_SETENV */
+
+#ifndef HAVE_SETLOGIN
+int setlogin(const char *name);
+#endif /* !HAVE_SETLOGIN */
+
+#ifndef HAVE_INNETGR
+int innetgr(const char *netgroup, const char *host, 
+            const char *user, const char *domain);
+#endif /* HAVE_INNETGR */
+
+#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
+int seteuid(uid_t euid);
+#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */
+
+#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
+int setegid(uid_t egid);
+#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
+
+#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR)
+const char *strerror(int e);
+#endif 
+
+
+#ifndef HAVE_UTIMES
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+       long tv_sec;
+       long tv_usec;
+}
+#endif /* HAVE_STRUCT_TIMEVAL */
+
+int utimes(char *filename, struct timeval *tvp);
+#endif /* HAVE_UTIMES */
+
+
+#endif /* _BSD_MISC_H */
diff --git a/openssh/openbsd-compat/bsd-nextstep.c b/openssh/openbsd-compat/bsd-nextstep.c
new file mode 100644 (file)
index 0000000..f3c1fb6
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+RCSID("$Id$");
+
+#ifdef HAVE_NEXT
+#include <errno.h>
+#include <sys/wait.h>
+#include "bsd-nextstep.h"
+
+pid_t 
+posix_wait(int *status)
+{
+       union wait statusp;
+       pid_t wait_pid;
+
+       #undef wait                     /* Use NeXT's wait() function */
+       wait_pid = wait(&statusp);
+       if (status)
+               *status = (int) statusp.w_status;
+
+       return wait_pid;
+}
+
+int
+tcgetattr(int fd, struct termios *t)
+{
+       return (ioctl(fd, TIOCGETA, t));
+}
+
+int
+tcsetattr(int fd, int opt, const struct termios *t)
+{
+       struct termios localterm;
+
+       if (opt & TCSASOFT) {
+               localterm = *t;
+               localterm.c_cflag |= CIGNORE;
+               t = &localterm;
+       }
+       switch (opt & ~TCSASOFT) {
+       case TCSANOW:
+               return (ioctl(fd, TIOCSETA, t));
+       case TCSADRAIN:
+               return (ioctl(fd, TIOCSETAW, t));
+       case TCSAFLUSH:
+               return (ioctl(fd, TIOCSETAF, t));
+       default:
+               errno = EINVAL;
+               return (-1);
+       }
+}
+
+int tcsetpgrp(int fd, pid_t pgrp)
+{
+       return (ioctl(fd, TIOCSPGRP, &pgrp));
+}
+
+speed_t cfgetospeed(const struct termios *t)
+{
+       return (t->c_ospeed);
+}
+
+speed_t cfgetispeed(const struct termios *t)
+{
+       return (t->c_ispeed);
+}
+
+int
+cfsetospeed(struct termios *t,int speed)
+{
+       t->c_ospeed = speed;
+       return (0);
+}
+
+int
+cfsetispeed(struct termios *t, int speed)
+{
+       t->c_ispeed = speed;
+       return (0);
+}
+#endif /* HAVE_NEXT */
diff --git a/openssh/openbsd-compat/bsd-nextstep.h b/openssh/openbsd-compat/bsd-nextstep.h
new file mode 100644 (file)
index 0000000..fb7cb15
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* $Id$ */
+
+#ifndef _NEXT_POSIX_H
+#define _NEXT_POSIX_H
+
+#ifdef HAVE_NEXT
+#include <sys/dir.h>
+
+/* NGROUPS_MAX is behind -lposix.  Use the BSD version which is NGROUPS */
+#undef NGROUPS_MAX
+#define NGROUPS_MAX NGROUPS
+
+/* NeXT's readdir() is BSD (struct direct) not POSIX (struct dirent) */
+#define dirent direct
+
+/* Swap out NeXT's BSD wait() for a more POSIX complient one */
+pid_t posix_wait(int *status);
+#define wait(a) posix_wait(a)
+
+/* #ifdef wrapped functions that need defining for clean compiling */
+pid_t getppid(void);
+void vhangup(void);
+int innetgr(const char *netgroup, const char *host, const char *user, 
+            const char *domain);
+
+/* TERMCAP */
+int tcgetattr(int fd, struct termios *t);
+int tcsetattr(int fd, int opt, const struct termios *t);
+int tcsetpgrp(int fd, pid_t pgrp);
+speed_t cfgetospeed(const struct termios *t);
+speed_t cfgetispeed(const struct termios *t);
+int cfsetospeed(struct termios *t, int speed);
+int cfsetispeed(struct termios *t, int speed);
+#endif /* HAVE_NEXT */
+#endif /* _NEXT_POSIX_H */
diff --git a/openssh/openbsd-compat/bsd-snprintf.c b/openssh/openbsd-compat/bsd-snprintf.c
new file mode 100644 (file)
index 0000000..cf3665a
--- /dev/null
@@ -0,0 +1,744 @@
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ * 
+ *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats. 
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH
+ *    Welcome to the world of %lld and %qd support.  With other
+ *    long long support.  This is needed for sftp-server to work
+ *    right.
+ *
+ *  Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH
+ *    Removed all hint of VARARGS stuff and banished it to the void,
+ *    and did a bit of KNF style work to make things a bit more
+ *    acceptable.  Consider stealing from mutt or enlightenment.
+ **************************************************************/
+
+#include "includes.h"
+
+RCSID("$Id$");
+
+#if defined(BROKEN_SNPRINTF)           /* For those with broken snprintf() */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+
+static void 
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
+       int min, int max);
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
+       int min, int max, int flags);
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+      int min, int max, int flags);
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS     (1 << 0)
+#define DP_F_PLUS      (1 << 1)
+#define DP_F_SPACE     (1 << 2)
+#define DP_F_NUM       (1 << 3)
+#define DP_F_ZERO      (1 << 4)
+#define DP_F_UP        (1 << 5)
+#define DP_F_UNSIGNED  (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT     1
+#define DP_C_LONG      2
+#define DP_C_LDOUBLE   3
+#define DP_C_LONG_LONG 4
+
+#define char_to_int(p) (p - '0')
+#define abs_val(p) (p < 0 ? -p : p)
+
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+       char *strvalue;
+       char ch;
+       long value;
+       long double fvalue;
+       int min = 0;
+       int max = -1;
+       int state = DP_S_DEFAULT;
+       int flags = 0;
+       int cflags = 0;
+       size_t currlen = 0;
+  
+       ch = *format++;
+
+       while (state != DP_S_DONE) {
+               if ((ch == '\0') || (currlen >= maxlen)) 
+                       state = DP_S_DONE;
+
+               switch(state) {
+                       case DP_S_DEFAULT:
+                               if (ch == '%') 
+                                       state = DP_S_FLAGS;
+                               else 
+                                       dopr_outch(buffer, &currlen, maxlen, ch);
+                               ch = *format++;
+                               break;
+                       case DP_S_FLAGS:
+                               switch (ch) {
+                                       case '-':
+                                               flags |= DP_F_MINUS;
+                                               ch = *format++;
+                                               break;
+                                       case '+':
+                                               flags |= DP_F_PLUS;
+                                               ch = *format++;
+                                               break;
+                                       case ' ':
+                                               flags |= DP_F_SPACE;
+                                               ch = *format++;
+                                               break;
+                                       case '#':
+                                               flags |= DP_F_NUM;
+                                               ch = *format++;
+                                               break;
+                                       case '0':
+                                               flags |= DP_F_ZERO;
+                                               ch = *format++;
+                                               break;
+                                       default:
+                                               state = DP_S_MIN;
+                                               break;
+                               }
+                               break;
+                       case DP_S_MIN:
+                               if (isdigit((unsigned char)ch)) {
+                                       min = 10*min + char_to_int (ch);
+                                       ch = *format++;
+                               } else if (ch == '*') {
+                                       min = va_arg (args, int);
+                                       ch = *format++;
+                                       state = DP_S_DOT;
+                               } else 
+                                       state = DP_S_DOT;
+                               break;
+                       case DP_S_DOT:
+                               if (ch == '.') {
+                                       state = DP_S_MAX;
+                                       ch = *format++;
+                               } else 
+                                       state = DP_S_MOD;
+                               break;
+                       case DP_S_MAX:
+                               if (isdigit((unsigned char)ch)) {
+                                       if (max < 0)
+                                               max = 0;
+                                       max = 10*max + char_to_int(ch);
+                                       ch = *format++;
+                               } else if (ch == '*') {
+                                       max = va_arg (args, int);
+                                       ch = *format++;
+                                       state = DP_S_MOD;
+                               } else 
+                                       state = DP_S_MOD;
+                               break;
+                       case DP_S_MOD:
+                               switch (ch) {
+                                       case 'h':
+                                               cflags = DP_C_SHORT;
+                                               ch = *format++;
+                                               break;
+                                       case 'l':
+                                               cflags = DP_C_LONG;
+                                               ch = *format++;
+                                               if (ch == 'l') {
+                                                       cflags = DP_C_LONG_LONG;
+                                                       ch = *format++;
+                                               }
+                                               break;
+                                       case 'q':
+                                               cflags = DP_C_LONG_LONG;
+                                               ch = *format++;
+                                               break;
+                                       case 'L':
+                                               cflags = DP_C_LDOUBLE;
+                                               ch = *format++;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               state = DP_S_CONV;
+                               break;
+                       case DP_S_CONV:
+                               switch (ch) {
+                                       case 'd':
+                                       case 'i':
+                                               if (cflags == DP_C_SHORT) 
+                                                       value = va_arg(args, int);
+                                               else if (cflags == DP_C_LONG)
+                                                       value = va_arg(args, long int);
+                                               else if (cflags == DP_C_LONG_LONG)
+                                                       value = va_arg (args, long long);
+                                               else
+                                                       value = va_arg (args, int);
+                                               fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+                                               break;
+                                       case 'o':
+                                               flags |= DP_F_UNSIGNED;
+                                               if (cflags == DP_C_SHORT)
+                                                       value = va_arg(args, unsigned int);
+                                               else if (cflags == DP_C_LONG)
+                                                       value = va_arg(args, unsigned long int);
+                                               else if (cflags == DP_C_LONG_LONG)
+                                                       value = va_arg(args, unsigned long long);
+                                               else
+                                                       value = va_arg(args, unsigned int);
+                                               fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+                                               break;
+                                       case 'u':
+                                               flags |= DP_F_UNSIGNED;
+                                               if (cflags == DP_C_SHORT)
+                                                       value = va_arg(args, unsigned int);
+                                               else if (cflags == DP_C_LONG)
+                                                       value = va_arg(args, unsigned long int);
+                                               else if (cflags == DP_C_LONG_LONG)
+                                                       value = va_arg(args, unsigned long long);
+                                               else
+                                                       value = va_arg(args, unsigned int);
+                                               fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+                                               break;
+                                       case 'X':
+                                               flags |= DP_F_UP;
+                                       case 'x':
+                                               flags |= DP_F_UNSIGNED;
+                                               if (cflags == DP_C_SHORT)
+                                                       value = va_arg(args, unsigned int);
+                                               else if (cflags == DP_C_LONG)
+                                                       value = va_arg(args, unsigned long int);
+                                               else if (cflags == DP_C_LONG_LONG)
+                                                       value = va_arg(args, unsigned long long);
+                                               else
+                                                       value = va_arg(args, unsigned int);
+                                               fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+                                               break;
+                                       case 'f':
+                                               if (cflags == DP_C_LDOUBLE)
+                                                       fvalue = va_arg(args, long double);
+                                               else
+                                                       fvalue = va_arg(args, double);
+                                               /* um, floating point? */
+                                               fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+                                               break;
+                                       case 'E':
+                                               flags |= DP_F_UP;
+                                       case 'e':
+                                               if (cflags == DP_C_LDOUBLE)
+                                                       fvalue = va_arg(args, long double);
+                                               else
+                                                       fvalue = va_arg(args, double);
+                                               break;
+                                       case 'G':
+                                               flags |= DP_F_UP;
+                                       case 'g':
+                                               if (cflags == DP_C_LDOUBLE)
+                                                       fvalue = va_arg(args, long double);
+                                               else
+                                                       fvalue = va_arg(args, double);
+                                               break;
+                                       case 'c':
+                                               dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+                                               break;
+                                       case 's':
+                                               strvalue = va_arg(args, char *);
+                                               if (max < 0) 
+                                                       max = maxlen; /* ie, no max */
+                                               fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+                                               break;
+                                       case 'p':
+                                               strvalue = va_arg(args, void *);
+                                               fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+                                               break;
+                                       case 'n':
+                                               if (cflags == DP_C_SHORT) {
+                                                       short int *num;
+                                                       num = va_arg(args, short int *);
+                                                       *num = currlen;
+                                               } else if (cflags == DP_C_LONG) {
+                                                       long int *num;
+                                                       num = va_arg(args, long int *);
+                                                       *num = currlen;
+                                               } else if (cflags == DP_C_LONG_LONG) {
+                                                       long long *num;
+                                                       num = va_arg(args, long long *);
+                                                       *num = currlen;
+                                               } else {
+                                                       int *num;
+                                                       num = va_arg(args, int *);
+                                                       *num = currlen;
+                                               }
+                                               break;
+                                       case '%':
+                                               dopr_outch(buffer, &currlen, maxlen, ch);
+                                               break;
+                                       case 'w': /* not supported yet, treat as next char */
+                                               ch = *format++;
+                                               break;
+                                       default: /* Unknown, skip */
+                                       break;
+                               }
+                               ch = *format++;
+                               state = DP_S_DEFAULT;
+                               flags = cflags = min = 0;
+                               max = -1;
+                               break;
+                       case DP_S_DONE:
+                               break;
+                       default: /* hmm? */
+                               break; /* some picky compilers need this */
+               }
+       }
+       if (currlen < maxlen - 1) 
+               buffer[currlen] = '\0';
+       else 
+               buffer[maxlen - 1] = '\0';
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+       char *value, int flags, int min, int max)
+{
+       int padlen, strln;     /* amount to pad */
+       int cnt = 0;
+  
+       if (value == 0) 
+               value = "<NULL>";
+
+       for (strln = 0; value[strln]; ++strln); /* strlen */
+       padlen = min - strln;
+       if (padlen < 0) 
+               padlen = 0;
+       if (flags & DP_F_MINUS) 
+               padlen = -padlen; /* Left Justify */
+
+       while ((padlen > 0) && (cnt < max)) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               --padlen;
+               ++cnt;
+       }
+       while (*value && (cnt < max)) {
+               dopr_outch(buffer, currlen, maxlen, *value++);
+               ++cnt;
+       }
+       while ((padlen < 0) && (cnt < max)) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               ++padlen;
+               ++cnt;
+       }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+       long value, int base, int min, int max, int flags)
+{
+       unsigned long uvalue;
+       char convert[20];
+       int signvalue = 0;
+       int place = 0;
+       int spadlen = 0; /* amount to space pad */
+       int zpadlen = 0; /* amount to zero pad */
+       int caps = 0;
+  
+       if (max < 0)
+               max = 0;
+
+       uvalue = value;
+
+       if (!(flags & DP_F_UNSIGNED)) {
+               if (value < 0) {
+                       signvalue = '-';
+                       uvalue = -value;
+               } else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+                       signvalue = '+';
+               else if (flags & DP_F_SPACE)
+                       signvalue = ' ';
+       }
+  
+       if (flags & DP_F_UP) 
+               caps = 1; /* Should characters be upper case? */
+
+       do {
+               convert[place++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")
+                       [uvalue % (unsigned)base];
+               uvalue = (uvalue / (unsigned)base );
+       } while (uvalue && (place < 20));
+       if (place == 20) 
+               place--;
+       convert[place] = 0;
+
+       zpadlen = max - place;
+       spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+       if (zpadlen < 0)
+               zpadlen = 0;
+       if (spadlen < 0)
+               spadlen = 0;
+       if (flags & DP_F_ZERO) {
+               zpadlen = MAX(zpadlen, spadlen);
+               spadlen = 0;
+       }
+       if (flags & DP_F_MINUS) 
+               spadlen = -spadlen; /* Left Justifty */
+
+
+       /* Spaces */
+       while (spadlen > 0) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               --spadlen;
+       }
+
+       /* Sign */
+       if (signvalue) 
+               dopr_outch(buffer, currlen, maxlen, signvalue);
+
+       /* Zeros */
+       if (zpadlen > 0) {
+               while (zpadlen > 0) {
+                       dopr_outch(buffer, currlen, maxlen, '0');
+                       --zpadlen;
+               }
+       }
+
+       /* Digits */
+       while (place > 0) 
+               dopr_outch(buffer, currlen, maxlen, convert[--place]);
+  
+       /* Left Justified spaces */
+       while (spadlen < 0) {
+               dopr_outch (buffer, currlen, maxlen, ' ');
+               ++spadlen;
+       }
+}
+
+static long double 
+pow10(int exp)
+{
+       long double result = 1;
+
+       while (exp) {
+               result *= 10;
+               exp--;
+       }
+  
+       return result;
+}
+
+static long 
+round(long double value)
+{
+       long intpart = value;
+
+       value -= intpart;
+       if (value >= 0.5)
+               intpart++;
+
+       return intpart;
+}
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+      int min, int max, int flags)
+{
+       char iconvert[20];
+       char fconvert[20];
+       int signvalue = 0;
+       int iplace = 0;
+       int fplace = 0;
+       int padlen = 0; /* amount to pad */
+       int zpadlen = 0; 
+       int caps = 0;
+       long intpart;
+       long fracpart;
+       long double ufvalue;
+  
+       /* 
+        * AIX manpage says the default is 0, but Solaris says the default
+        * is 6, and sprintf on AIX defaults to 6
+        */
+       if (max < 0)
+               max = 6;
+
+       ufvalue = abs_val(fvalue);
+
+       if (fvalue < 0)
+               signvalue = '-';
+       else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+               signvalue = '+';
+       else if (flags & DP_F_SPACE)
+               signvalue = ' ';
+
+       intpart = ufvalue;
+
+       /* 
+        * Sorry, we only support 9 digits past the decimal because of our 
+        * conversion method
+        */
+       if (max > 9)
+               max = 9;
+
+       /* We "cheat" by converting the fractional part to integer by
+        * multiplying by a factor of 10
+        */
+       fracpart = round((pow10 (max)) * (ufvalue - intpart));
+
+       if (fracpart >= pow10 (max)) {
+               intpart++;
+               fracpart -= pow10 (max);
+       }
+
+       /* Convert integer part */
+       do {
+               iconvert[iplace++] =
+                 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
+               intpart = (intpart / 10);
+       } while(intpart && (iplace < 20));
+       if (iplace == 20) 
+               iplace--;
+       iconvert[iplace] = 0;
+
+       /* Convert fractional part */
+       do {
+               fconvert[fplace++] =
+                 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
+               fracpart = (fracpart / 10);
+       } while(fracpart && (fplace < 20));
+       if (fplace == 20) 
+               fplace--;
+       fconvert[fplace] = 0;
+
+       /* -1 for decimal point, another -1 if we are printing a sign */
+       padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+       zpadlen = max - fplace;
+       if (zpadlen < 0)
+               zpadlen = 0;
+       if (padlen < 0) 
+               padlen = 0;
+       if (flags & DP_F_MINUS) 
+               padlen = -padlen; /* Left Justifty */
+
+       if ((flags & DP_F_ZERO) && (padlen > 0)) {
+               if (signvalue) {
+                       dopr_outch(buffer, currlen, maxlen, signvalue);
+                       --padlen;
+                       signvalue = 0;
+               }
+               while (padlen > 0) {
+                       dopr_outch(buffer, currlen, maxlen, '0');
+                       --padlen;
+               }
+       }
+       while (padlen > 0) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               --padlen;
+       }
+       if (signvalue) 
+               dopr_outch(buffer, currlen, maxlen, signvalue);
+
+       while (iplace > 0) 
+               dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+       /*
+        * Decimal point.  This should probably use locale to find the correct
+        * char to print out.
+        */
+       dopr_outch(buffer, currlen, maxlen, '.');
+
+       while (fplace > 0) 
+               dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+
+       while (zpadlen > 0) {
+               dopr_outch(buffer, currlen, maxlen, '0');
+               --zpadlen;
+       }
+
+       while (padlen < 0) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               ++padlen;
+       }
+}
+
+static void 
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+       if (*currlen < maxlen)
+               buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int 
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+       str[0] = 0;
+       dopr(str, count, fmt, args);
+
+       return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int 
+snprintf(char *str,size_t count,const char *fmt,...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       (void) vsnprintf(str, count, fmt, ap);
+       va_end(ap);
+
+       return(strlen(str));
+}
+
+#ifdef TEST_SNPRINTF
+int 
+main(void)
+{
+#define LONG_STRING 1024
+       char buf1[LONG_STRING];
+       char buf2[LONG_STRING];
+       char *fp_fmt[] = {
+               "%-1.5f",
+               "%1.5f",
+               "%123.9f",
+               "%10.5f",
+               "% 10.5f",
+               "%+22.9f",
+               "%+4.9f",
+               "%01.3f",
+               "%4f",
+               "%3.1f",
+               "%3.2f",
+               NULL
+       };
+       double fp_nums[] = { 
+               -1.5, 
+               134.21, 
+               91340.2, 
+               341.1234, 
+               0203.9, 
+               0.96, 
+               0.996, 
+               0.9996, 
+               1.996, 
+               4.136, 
+               0
+       };
+       char *int_fmt[] = {
+               "%-1.5d",
+               "%1.5d",
+               "%123.9d",
+               "%5.5d",
+               "%10.5d",
+               "% 10.5d",
+               "%+22.33d",
+               "%01.3d",
+               "%4d",
+               "%lld",
+               "%qd",
+               NULL
+       };
+       long long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 9999999 };
+       int x, y;
+       int fail = 0;
+       int num = 0;
+
+       printf("Testing snprintf format codes against system sprintf...\n");
+
+       for (x = 0; fp_fmt[x] != NULL ; x++) {
+               for (y = 0; fp_nums[y] != 0 ; y++) {
+                       snprintf(buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
+                       sprintf (buf2, fp_fmt[x], fp_nums[y]);
+                       if (strcmp (buf1, buf2)) {
+                               printf("snprintf doesn't match Format: %s\n\t"
+                                       "snprintf = %s\n\tsprintf  = %s\n", 
+                                       fp_fmt[x], buf1, buf2);
+                               fail++;
+                       }
+                       num++;
+               }
+       }
+       for (x = 0; int_fmt[x] != NULL ; x++) {
+               for (y = 0; int_nums[y] != 0 ; y++) {
+                       snprintf(buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
+                       sprintf(buf2, int_fmt[x], int_nums[y]);
+                       if (strcmp (buf1, buf2)) {
+                               printf("snprintf doesn't match Format: %s\n\t"
+                                      "snprintf = %s\n\tsprintf  = %s\n", 
+                                       int_fmt[x], buf1, buf2);
+                               fail++;
+                       }
+                       num++;
+               }
+       }
+       printf("%d tests failed out of %d.\n", fail, num);
+       return(0);
+}
+#endif /* SNPRINTF_TEST */
+
+#endif /* !HAVE_SNPRINTF */
diff --git a/openssh/openbsd-compat/bsd-snprintf.h b/openssh/openbsd-compat/bsd-snprintf.h
new file mode 100644 (file)
index 0000000..ce5a1f4
--- /dev/null
@@ -0,0 +1,19 @@
+/* $Id$ */
+
+#ifndef _BSD_SNPRINTF_H
+#define _BSD_SNPRINTF_H
+
+#include "config.h"
+
+#include <sys/types.h> /* For size_t */
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t count, const char *fmt, ...);
+#endif /* !HAVE_SNPRINTF */
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+#endif /* !HAVE_SNPRINTF */
+
+
+#endif /* _BSD_SNPRINTF_H */
diff --git a/openssh/openbsd-compat/bsd-waitpid.c b/openssh/openbsd-compat/bsd-waitpid.c
new file mode 100644 (file)
index 0000000..c2178d6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+RCSID("$Id$");
+
+#ifndef HAVE_WAITPID 
+#include <errno.h>
+#include <sys/wait.h>
+#include "bsd-waitpid.h"
+
+pid_t
+waitpid(int pid, int *stat_loc, int options)
+{
+       union wait statusp;
+       pid_t wait_pid;
+
+       if (pid <= 0) {
+               if (pid != -1) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               pid = 0;   /* wait4() wants pid=0 for indiscriminate wait. */
+       }
+        wait_pid = wait4(pid, &statusp, options, NULL);
+       if (stat_loc)
+               *stat_loc = (int) statusp.w_status;            
+
+        return wait_pid;                               
+}
+
+#endif /* !HAVE_WAITPID */
diff --git a/openssh/openbsd-compat/bsd-waitpid.h b/openssh/openbsd-compat/bsd-waitpid.h
new file mode 100644 (file)
index 0000000..bc50189
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* $Id$ */
+
+#ifndef _BSD_WAITPID_H
+#define _BSD_WAITPID_H
+
+#ifndef HAVE_WAITPID
+/* Clean out any potental issues */
+#undef WIFEXITED
+#undef WIFSTOPPED
+#undef WIFSIGNALED
+
+/* Define required functions to mimic a POSIX look and feel */
+#define _W_INT(w)      (*(int*)&(w))   /* convert union wait to int */
+#define WIFEXITED(w)   (!((_W_INT(w)) & 0377))
+#define WIFSTOPPED(w)  ((_W_INT(w)) & 0100)
+#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w))
+#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1)
+#define WTERMSIG(w)    (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1)
+#define WCOREFLAG      0x80
+#define WCOREDUMP(w)   ((_W_INT(w)) & WCOREFLAG)
+
+/* Prototype */
+pid_t waitpid(int pid, int *stat_loc, int options);
+
+#endif /* !HAVE_WAITPID */
+#endif /* _BSD_WAITPID_H */
diff --git a/openssh/openbsd-compat/daemon.c b/openssh/openbsd-compat/daemon.c
new file mode 100644 (file)
index 0000000..f704a90
--- /dev/null
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_DAEMON
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: daemon.c,v 1.2 1996/08/19 08:22:13 tholo Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+int
+daemon(nochdir, noclose)
+       int nochdir, noclose;
+{
+       int fd;
+
+       switch (fork()) {
+       case -1:
+               return (-1);
+       case 0:
+               break;
+       default:
+#ifdef HAVE_CYGWIN
+               /*
+                * This sleep avoids a race condition which kills the
+                * child process if parent is started by a NT/W2K service.
+                */
+               sleep(1);
+#endif
+               _exit(0);
+       }
+
+       if (setsid() == -1)
+               return (-1);
+
+       if (!nochdir)
+               (void)chdir("/");
+
+       if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+               (void)dup2(fd, STDIN_FILENO);
+               (void)dup2(fd, STDOUT_FILENO);
+               (void)dup2(fd, STDERR_FILENO);
+               if (fd > 2)
+                       (void)close (fd);
+       }
+       return (0);
+}
+
+#endif /* !HAVE_DAEMON */
+
diff --git a/openssh/openbsd-compat/daemon.h b/openssh/openbsd-compat/daemon.h
new file mode 100644 (file)
index 0000000..241867f
--- /dev/null
@@ -0,0 +1,11 @@
+/* $Id$ */
+
+#ifndef _BSD_DAEMON_H
+#define _BSD_DAEMON_H
+
+#include "config.h"
+#ifndef HAVE_DAEMON
+int daemon(int nochdir, int noclose);
+#endif /* !HAVE_DAEMON */
+
+#endif /* _BSD_DAEMON_H */
diff --git a/openssh/openbsd-compat/dirname.c b/openssh/openbsd-compat/dirname.c
new file mode 100644 (file)
index 0000000..a76a1dc
--- /dev/null
@@ -0,0 +1,80 @@
+/*     $OpenBSD: dirname.c,v 1.5 2001/06/27 00:58:54 lebel Exp $       */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#ifndef HAVE_DIRNAME
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: dirname.c,v 1.5 2001/06/27 00:58:54 lebel Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+
+char *
+dirname(path)
+       const char *path;
+{
+       static char bname[MAXPATHLEN];
+       register const char *endp;
+
+       /* Empty or NULL string gets treated as "." */
+       if (path == NULL || *path == '\0') {
+               (void)strcpy(bname, ".");
+               return(bname);
+       }
+
+       /* Strip trailing slashes */
+       endp = path + strlen(path) - 1;
+       while (endp > path && *endp == '/')
+               endp--;
+
+       /* Find the start of the dir */
+       while (endp > path && *endp != '/')
+               endp--;
+
+       /* Either the dir is "/" or there are no slashes */
+       if (endp == path) {
+               (void)strcpy(bname, *endp == '/' ? "/" : ".");
+               return(bname);
+       } else {
+               do {
+                       endp--;
+               } while (endp > path && *endp == '/');
+       }
+
+       if (endp - path + 1 > sizeof(bname)) {
+               errno = ENAMETOOLONG;
+               return(NULL);
+       }
+       strlcpy(bname, path, endp - path + 2);
+       return(bname);
+}
+#endif
diff --git a/openssh/openbsd-compat/dirname.h b/openssh/openbsd-compat/dirname.h
new file mode 100644 (file)
index 0000000..1d61dd0
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef HAVE_DIRNAME
+
+char *dirname(const char *path);
+
+#endif
diff --git a/openssh/openbsd-compat/fake-gai-errnos.h b/openssh/openbsd-compat/fake-gai-errnos.h
new file mode 100644 (file)
index 0000000..af51a1c
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * fake library for ssh
+ *
+ * This file is included in getaddrinfo.c and getnameinfo.c.
+ * See getaddrinfo.c and getnameinfo.c.
+ */
+
+/* $Id$ */
+
+/* for old netdb.h */
+#ifndef EAI_NODATA
+#define EAI_NODATA     1
+#define EAI_MEMORY     2
+#endif
diff --git a/openssh/openbsd-compat/fake-getaddrinfo.c b/openssh/openbsd-compat/fake-getaddrinfo.c
new file mode 100644 (file)
index 0000000..5a1ad97
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * fake library for ssh
+ *
+ * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
+ * These funtions are defined in rfc2133.
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For exapmle, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ */
+
+#include "includes.h"
+#include "ssh.h"
+
+RCSID("$Id$");
+
+#ifndef HAVE_GAI_STRERROR
+char *gai_strerror(int ecode)
+{
+       switch (ecode) {
+               case EAI_NODATA:
+                       return "no address associated with hostname.";
+               case EAI_MEMORY:
+                       return "memory allocation failure.";
+               default:
+                       return "unknown error.";
+       }
+}    
+#endif /* !HAVE_GAI_STRERROR */
+
+#ifndef HAVE_FREEADDRINFO
+void freeaddrinfo(struct addrinfo *ai)
+{
+       struct addrinfo *next;
+
+       do {
+               next = ai->ai_next;
+               free(ai);
+       } while (NULL != (ai = next));
+}
+#endif /* !HAVE_FREEADDRINFO */
+
+#ifndef HAVE_GETADDRINFO
+static struct addrinfo *malloc_ai(int port, u_long addr)
+{
+       struct addrinfo *ai;
+
+       ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+       if (ai == NULL)
+               return(NULL);
+       
+       memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+       
+       ai->ai_addr = (struct sockaddr *)(ai + 1);
+       /* XXX -- ssh doesn't use sa_len */
+       ai->ai_addrlen = sizeof(struct sockaddr_in);
+       ai->ai_addr->sa_family = ai->ai_family = AF_INET;
+
+       ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
+       ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
+       
+       return(ai);
+}
+
+int getaddrinfo(const char *hostname, const char *servname, 
+                const struct addrinfo *hints, struct addrinfo **res)
+{
+       struct addrinfo *cur, *prev = NULL;
+       struct hostent *hp;
+       struct in_addr in;
+       int i, port;
+
+       if (servname)
+               port = htons(atoi(servname));
+       else
+               port = 0;
+
+       if (hints && hints->ai_flags & AI_PASSIVE) {
+               if (NULL != (*res = malloc_ai(port, htonl(0x00000000))))
+                       return 0;
+               else
+                       return EAI_MEMORY;
+       }
+               
+       if (!hostname) {
+               if (NULL != (*res = malloc_ai(port, htonl(0x7f000001))))
+                       return 0;
+               else
+                       return EAI_MEMORY;
+       }
+       
+       if (inet_aton(hostname, &in)) {
+               if (NULL != (*res = malloc_ai(port, in.s_addr)))
+                       return 0;
+               else
+                       return EAI_MEMORY;
+       }
+       
+       hp = gethostbyname(hostname);
+       if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+               for (i = 0; hp->h_addr_list[i]; i++) {
+                       cur = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
+                       if (cur == NULL) {
+                               if (*res)
+                                       freeaddrinfo(*res);
+                               return EAI_MEMORY;
+                       }
+                       
+                       if (prev)
+                               prev->ai_next = cur;
+                       else
+                               *res = cur;
+
+                       prev = cur;
+               }
+               return 0;
+       }
+       
+       return EAI_NODATA;
+}
+#endif /* !HAVE_GETADDRINFO */
diff --git a/openssh/openbsd-compat/fake-getaddrinfo.h b/openssh/openbsd-compat/fake-getaddrinfo.h
new file mode 100644 (file)
index 0000000..ba5e3fe
--- /dev/null
@@ -0,0 +1,47 @@
+/* $Id$ */
+
+#ifndef _FAKE_GETADDRINFO_H
+#define _FAKE_GETADDRINFO_H
+
+#include "config.h"
+
+#include "fake-gai-errnos.h"
+
+#ifndef AI_PASSIVE
+# define AI_PASSIVE        1
+# define AI_CANONNAME      2
+#endif
+
+#ifndef NI_NUMERICHOST
+# define NI_NUMERICHOST    2
+# define NI_NAMEREQD       4
+# define NI_NUMERICSERV    8
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+       int     ai_flags;       /* AI_PASSIVE, AI_CANONNAME */
+       int     ai_family;      /* PF_xxx */
+       int     ai_socktype;    /* SOCK_xxx */
+       int     ai_protocol;    /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+       size_t  ai_addrlen;     /* length of ai_addr */
+       char    *ai_canonname;  /* canonical name for hostname */
+       struct sockaddr *ai_addr;       /* binary address */
+       struct addrinfo *ai_next;       /* next structure in linked list */
+};
+#endif /* !HAVE_STRUCT_ADDRINFO */
+
+#ifndef HAVE_GETADDRINFO
+int getaddrinfo(const char *hostname, const char *servname, 
+                const struct addrinfo *hints, struct addrinfo **res);
+#endif /* !HAVE_GETADDRINFO */
+
+#ifndef HAVE_GAI_STRERROR
+char *gai_strerror(int ecode);
+#endif /* !HAVE_GAI_STRERROR */
+
+#ifndef HAVE_FREEADDRINFO
+void freeaddrinfo(struct addrinfo *ai);
+#endif /* !HAVE_FREEADDRINFO */
+
+#endif /* _FAKE_GETADDRINFO_H */
diff --git a/openssh/openbsd-compat/fake-getnameinfo.c b/openssh/openbsd-compat/fake-getnameinfo.c
new file mode 100644 (file)
index 0000000..8f6f19e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * fake library for ssh
+ *
+ * This file includes getnameinfo().
+ * These funtions are defined in rfc2133.
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For exapmle, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ */
+
+#include "includes.h"
+#include "ssh.h"
+
+RCSID("$Id$");
+
+#ifndef HAVE_GETNAMEINFO
+int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 
+                size_t hostlen, char *serv, size_t servlen, int flags)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+       struct hostent *hp;
+       char tmpserv[16];
+
+       if (serv) {
+               snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
+               if (strlen(tmpserv) >= servlen)
+                       return EAI_MEMORY;
+               else
+                       strcpy(serv, tmpserv);
+       }
+
+       if (host) {
+               if (flags & NI_NUMERICHOST) {
+                       if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
+                               return EAI_MEMORY;
+
+                       strcpy(host, inet_ntoa(sin->sin_addr));
+                       return 0;
+               } else {
+                       hp = gethostbyaddr((char *)&sin->sin_addr, 
+                               sizeof(struct in_addr), AF_INET);
+                       if (hp == NULL)
+                               return EAI_NODATA;
+                       
+                       if (strlen(hp->h_name) >= hostlen)
+                               return EAI_MEMORY;
+
+                       strcpy(host, hp->h_name);
+                       return 0;
+               }
+       }
+       return 0;
+}
+#endif /* !HAVE_GETNAMEINFO */
diff --git a/openssh/openbsd-compat/fake-getnameinfo.h b/openssh/openbsd-compat/fake-getnameinfo.h
new file mode 100644 (file)
index 0000000..b91c791
--- /dev/null
@@ -0,0 +1,20 @@
+/* $Id$ */
+
+#ifndef _FAKE_GETNAMEINFO_H
+#define _FAKE_GETNAMEINFO_H
+
+#include "config.h"
+
+#ifndef HAVE_GETNAMEINFO
+int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 
+                size_t hostlen, char *serv, size_t servlen, int flags);
+#endif /* !HAVE_GETNAMEINFO */
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif /* !NI_MAXSERV */
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif /* !NI_MAXHOST */
+
+#endif /* _FAKE_GETNAMEINFO_H */
diff --git a/openssh/openbsd-compat/fake-queue.h b/openssh/openbsd-compat/fake-queue.h
new file mode 100644 (file)
index 0000000..269af41
--- /dev/null
@@ -0,0 +1,490 @@
+/*     $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $  */
+/*     $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $       */
+
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef        _SYS_QUEUE_H_
+#define        _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists, 
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *slh_first; /* first element */                     \
+}
+#define        SLIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+#define SLIST_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *sle_next;  /* next element */                      \
+}
+/*
+ * Singly-linked List access methods.
+ */
+#define        SLIST_FIRST(head)       ((head)->slh_first)
+#define        SLIST_END(head)         NULL
+#define        SLIST_EMPTY(head)       (SLIST_FIRST(head) == SLIST_END(head))
+#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
+
+#define        SLIST_FOREACH(var, head, field)                                 \
+       for((var) = SLIST_FIRST(head);                                  \
+           (var) != SLIST_END(head);                                   \
+           (var) = SLIST_NEXT(var, field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define        SLIST_INIT(head) {                                              \
+       SLIST_FIRST(head) = SLIST_END(head);                            \
+}
+
+#define        SLIST_INSERT_AFTER(slistelm, elm, field) do {                   \
+       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+       (slistelm)->field.sle_next = (elm);                             \
+} while (0)
+
+#define        SLIST_INSERT_HEAD(head, elm, field) do {                        \
+       (elm)->field.sle_next = (head)->slh_first;                      \
+       (head)->slh_first = (elm);                                      \
+} while (0)
+
+#define        SLIST_REMOVE_HEAD(head, field) do {                             \
+       (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)                                          \
+struct name {                                                          \
+       struct type *lh_first;  /* first element */                     \
+}
+
+#define LIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+
+#define LIST_ENTRY(type)                                               \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List access methods
+ */
+#define        LIST_FIRST(head)                ((head)->lh_first)
+#define        LIST_END(head)                  NULL
+#define        LIST_EMPTY(head)                (LIST_FIRST(head) == LIST_END(head))
+#define        LIST_NEXT(elm, field)           ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field)                                 \
+       for((var) = LIST_FIRST(head);                                   \
+           (var)!= LIST_END(head);                                     \
+           (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define        LIST_INIT(head) do {                                            \
+       LIST_FIRST(head) = LIST_END(head);                              \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {                    \
+       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+               (listelm)->field.le_next->field.le_prev =               \
+                   &(elm)->field.le_next;                              \
+       (listelm)->field.le_next = (elm);                               \
+       (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (0)
+
+#define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
+       (elm)->field.le_prev = (listelm)->field.le_prev;                \
+       (elm)->field.le_next = (listelm);                               \
+       *(listelm)->field.le_prev = (elm);                              \
+       (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {                                \
+       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+       (head)->lh_first = (elm);                                       \
+       (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do {                                   \
+       if ((elm)->field.le_next != NULL)                               \
+               (elm)->field.le_next->field.le_prev =                   \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = (elm)->field.le_next;                   \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do {                            \
+       if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)     \
+               (elm2)->field.le_next->field.le_prev =                  \
+                   &(elm2)->field.le_next;                             \
+       (elm2)->field.le_prev = (elm)->field.le_prev;                   \
+       *(elm2)->field.le_prev = (elm2);                                \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *sqh_first; /* first element */                     \
+       struct type **sqh_last; /* addr of last next element */         \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head)                                 \
+       { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *sqe_next;  /* next element */                      \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define        SIMPLEQ_FIRST(head)         ((head)->sqh_first)
+#define        SIMPLEQ_END(head)           NULL
+#define        SIMPLEQ_EMPTY(head)         (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define        SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field)                              \
+       for((var) = SIMPLEQ_FIRST(head);                                \
+           (var) != SIMPLEQ_END(head);                                 \
+           (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define        SIMPLEQ_INIT(head) do {                                         \
+       (head)->sqh_first = NULL;                                       \
+       (head)->sqh_last = &(head)->sqh_first;                          \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)        \
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (head)->sqh_first = (elm);                                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.sqe_next = NULL;                                   \
+       *(head)->sqh_last = (elm);                                      \
+       (head)->sqh_last = &(elm)->field.sqe_next;                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (listelm)->field.sqe_next = (elm);                              \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do {                     \
+       if (((head)->sqh_first = (elm)->field.sqe_next) == NULL)        \
+               (head)->sqh_last = &(head)->sqh_first;                  \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *tqh_first; /* first element */                     \
+       struct type **tqh_last; /* addr of last next element */         \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)                                   \
+       { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+
+/* 
+ * tail queue access methods 
+ */
+#define        TAILQ_FIRST(head)               ((head)->tqh_first)
+#define        TAILQ_END(head)                 NULL
+#define        TAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname)                                     \
+       (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field)                               \
+       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define        TAILQ_EMPTY(head)                                               \
+       (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field)                                        \
+       for((var) = TAILQ_FIRST(head);                                  \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, field, headname)              \
+       for((var) = TAILQ_LAST(head, headname);                         \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define        TAILQ_INIT(head) do {                                           \
+       (head)->tqh_first = NULL;                                       \
+       (head)->tqh_last = &(head)->tqh_first;                          \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {                       \
+       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+               (head)->tqh_first->field.tqe_prev =                     \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (head)->tqh_first = (elm);                                      \
+       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {                       \
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = (head)->tqh_last;                       \
+       *(head)->tqh_last = (elm);                                      \
+       (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (listelm)->field.tqe_next = (elm);                              \
+       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (0)
+
+#define        TAILQ_INSERT_BEFORE(listelm, elm, field) do {                   \
+       (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+       (elm)->field.tqe_next = (listelm);                              \
+       *(listelm)->field.tqe_prev = (elm);                             \
+       (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {                            \
+       if (((elm)->field.tqe_next) != NULL)                            \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   (elm)->field.tqe_prev;                              \
+       else                                                            \
+               (head)->tqh_last = (elm)->field.tqe_prev;               \
+       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {                     \
+       if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)   \
+               (elm2)->field.tqe_next->field.tqe_prev =                \
+                   &(elm2)->field.tqe_next;                            \
+       else                                                            \
+               (head)->tqh_last = &(elm2)->field.tqe_next;             \
+       (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
+       *(elm2)->field.tqe_prev = (elm2);                               \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *cqh_first;         /* first element */             \
+       struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head)                                 \
+       { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *cqe_next;          /* next element */              \
+       struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue access methods 
+ */
+#define        CIRCLEQ_FIRST(head)             ((head)->cqh_first)
+#define        CIRCLEQ_LAST(head)              ((head)->cqh_last)
+#define        CIRCLEQ_END(head)               ((void *)(head))
+#define        CIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
+#define        CIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
+#define        CIRCLEQ_EMPTY(head)                                             \
+       (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field)                              \
+       for((var) = CIRCLEQ_FIRST(head);                                \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
+       for((var) = CIRCLEQ_LAST(head);                                 \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define        CIRCLEQ_INIT(head) do {                                         \
+       (head)->cqh_first = CIRCLEQ_END(head);                          \
+       (head)->cqh_last = CIRCLEQ_END(head);                           \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+       (elm)->field.cqe_prev = (listelm);                              \
+       if ((listelm)->field.cqe_next == CIRCLEQ_END(head))             \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+       (listelm)->field.cqe_next = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
+       (elm)->field.cqe_next = (listelm);                              \
+       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+       if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))             \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+       (listelm)->field.cqe_prev = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       (elm)->field.cqe_next = (head)->cqh_first;                      \
+       (elm)->field.cqe_prev = CIRCLEQ_END(head);                      \
+       if ((head)->cqh_last == CIRCLEQ_END(head))                      \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (head)->cqh_first->field.cqe_prev = (elm);              \
+       (head)->cqh_first = (elm);                                      \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.cqe_next = CIRCLEQ_END(head);                      \
+       (elm)->field.cqe_prev = (head)->cqh_last;                       \
+       if ((head)->cqh_first == CIRCLEQ_END(head))                     \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (head)->cqh_last->field.cqe_next = (elm);               \
+       (head)->cqh_last = (elm);                                       \
+} while (0)
+
+#define        CIRCLEQ_REMOVE(head, elm, field) do {                           \
+       if ((elm)->field.cqe_next == CIRCLEQ_END(head))                 \
+               (head)->cqh_last = (elm)->field.cqe_prev;               \
+       else                                                            \
+               (elm)->field.cqe_next->field.cqe_prev =                 \
+                   (elm)->field.cqe_prev;                              \
+       if ((elm)->field.cqe_prev == CIRCLEQ_END(head))                 \
+               (head)->cqh_first = (elm)->field.cqe_next;              \
+       else                                                            \
+               (elm)->field.cqe_prev->field.cqe_next =                 \
+                   (elm)->field.cqe_next;                              \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {                   \
+       if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head).cqh_last = (elm2);                               \
+       else                                                            \
+               (elm2)->field.cqe_next->field.cqe_prev = (elm2);        \
+       if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head).cqh_first = (elm2);                              \
+       else                                                            \
+               (elm2)->field.cqe_prev->field.cqe_next = (elm2);        \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/openssh/openbsd-compat/fake-regex.h b/openssh/openbsd-compat/fake-regex.h
new file mode 100644 (file)
index 0000000..8f7f6ed
--- /dev/null
@@ -0,0 +1,106 @@
+/*     $OpenBSD: regex.h,v 1.3 1997/09/21 10:45:48 niklas Exp $        */
+/*     $NetBSD: regex.h,v 1.4.6.1 1996/06/10 18:57:07 explorer Exp $   */
+
+/*-
+ * Copyright (c) 1992 Henry Spencer.
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)regex.h     8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _REGEX_H_
+#define        _REGEX_H_
+
+#include <sys/types.h>
+
+/* types */
+typedef off_t regoff_t;
+
+typedef struct {
+       int re_magic;
+       size_t re_nsub;         /* number of parenthesized subexpressions */
+       const char *re_endp;    /* end pointer for REG_PEND */
+       struct re_guts *re_g;   /* none of your business :-) */
+} regex_t;
+
+typedef struct {
+       regoff_t rm_so;         /* start of match */
+       regoff_t rm_eo;         /* end of match */
+} regmatch_t;
+
+/* regcomp() flags */
+#define        REG_BASIC       0000
+#define        REG_EXTENDED    0001
+#define        REG_ICASE       0002
+#define        REG_NOSUB       0004
+#define        REG_NEWLINE     0010
+#define        REG_NOSPEC      0020
+#define        REG_PEND        0040
+#define        REG_DUMP        0200
+
+/* regerror() flags */
+#define        REG_NOMATCH      1
+#define        REG_BADPAT       2
+#define        REG_ECOLLATE     3
+#define        REG_ECTYPE       4
+#define        REG_EESCAPE      5
+#define        REG_ESUBREG      6
+#define        REG_EBRACK       7
+#define        REG_EPAREN       8
+#define        REG_EBRACE       9
+#define        REG_BADBR       10
+#define        REG_ERANGE      11
+#define        REG_ESPACE      12
+#define        REG_BADRPT      13
+#define        REG_EMPTY       14
+#define        REG_ASSERT      15
+#define        REG_INVARG      16
+#define        REG_ATOI        255     /* convert name to number (!) */
+#define        REG_ITOA        0400    /* convert number to name (!) */
+
+/* regexec() flags */
+#define        REG_NOTBOL      00001
+#define        REG_NOTEOL      00002
+#define        REG_STARTEND    00004
+#define        REG_TRACE       00400   /* tracing of execution */
+#define        REG_LARGE       01000   /* force large representation */
+#define        REG_BACKR       02000   /* force use of backref code */
+
+int    regcomp(regex_t*, const char*, int);
+size_t regerror(int, const regex_t*, char*, size_t);
+int    regexec(const regex_t*, const char*, size_t, regmatch_t[], int);
+void   regfree(regex_t*);
+
+#endif /* !_REGEX_H_ */
diff --git a/openssh/openbsd-compat/fake-socket.h b/openssh/openbsd-compat/fake-socket.h
new file mode 100644 (file)
index 0000000..79f8ed4
--- /dev/null
@@ -0,0 +1,47 @@
+/* $Id$ */
+
+#ifndef _FAKE_SOCKET_H
+#define _FAKE_SOCKET_H
+
+#include "config.h"
+#include "sys/types.h"
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+# define       _SS_MAXSIZE     128     /* Implementation specific max size */
+# define       _SS_PADSIZE     (_SS_MAXSIZE - sizeof (struct sockaddr))
+
+struct sockaddr_storage {
+       struct  sockaddr ss_sa;
+       char            __ss_pad2[_SS_PADSIZE];
+};
+# define ss_family ss_sa.sa_family
+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+# define IN6_IS_ADDR_LOOPBACK(a) \
+       (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \
+        ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1))
+#endif /* !IN6_IS_ADDR_LOOPBACK */
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+       u_int8_t                s6_addr[16];
+};
+#endif /* !HAVE_STRUCT_IN6_ADDR */
+
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+struct sockaddr_in6 {
+   unsigned short sin6_family;
+       u_int16_t sin6_port;
+       u_int32_t sin6_flowinfo;
+       struct in6_addr sin6_addr;
+};
+#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
+
+#ifndef AF_INET6
+/* Define it to something that should never appear */
+#define AF_INET6 AF_MAX
+#endif
+
+#endif /* !_FAKE_SOCKET_H */
+
diff --git a/openssh/openbsd-compat/getcwd.c b/openssh/openbsd-compat/getcwd.c
new file mode 100644 (file)
index 0000000..de3bacc
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 1989, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if !defined(HAVE_GETCWD)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: getcwd.c,v 1.6 2000/07/19 15:25:13 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/dir.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "includes.h"
+
+#define        ISDOT(dp) \
+       (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
+           (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+
+char *
+getcwd(char *pt,size_t size)
+{
+       register struct dirent *dp;
+       register DIR *dir = NULL;
+       register dev_t dev;
+       register ino_t ino;
+       register int first;
+       register char *bpt, *bup;
+       struct stat s;
+       dev_t root_dev;
+       ino_t root_ino;
+       size_t ptsize, upsize;
+       int save_errno;
+       char *ept, *eup, *up;
+
+       /*
+        * If no buffer specified by the user, allocate one as necessary.
+        * If a buffer is specified, the size has to be non-zero.  The path
+        * is built from the end of the buffer backwards.
+        */
+       if (pt) {
+               ptsize = 0;
+               if (!size) {
+                       errno = EINVAL;
+                       return (NULL);
+               }
+               ept = pt + size;
+       } else {
+               if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
+                       return (NULL);
+               ept = pt + ptsize;
+       }
+       bpt = ept - 1;
+       *bpt = '\0';
+
+       /*
+        * Allocate bytes (1024 - malloc space) for the string of "../"'s.
+        * Should always be enough (it's 340 levels).  If it's not, allocate
+        * as necessary.  Special * case the first stat, it's ".", not "..".
+        */
+       if ((up = malloc(upsize = 1024 - 4)) == NULL)
+               goto err;
+       eup = up + MAXPATHLEN;
+       bup = up;
+       up[0] = '.';
+       up[1] = '\0';
+
+       /* Save root values, so know when to stop. */
+       if (stat("/", &s))
+               goto err;
+       root_dev = s.st_dev;
+       root_ino = s.st_ino;
+
+       errno = 0;                      /* XXX readdir has no error return. */
+
+       for (first = 1;; first = 0) {
+               /* Stat the current level. */
+               if (lstat(up, &s))
+                       goto err;
+
+               /* Save current node values. */
+               ino = s.st_ino;
+               dev = s.st_dev;
+
+               /* Check for reaching root. */
+               if (root_dev == dev && root_ino == ino) {
+                       *--bpt = '/';
+                       /*
+                        * It's unclear that it's a requirement to copy the
+                        * path to the beginning of the buffer, but it's always
+                        * been that way and stuff would probably break.
+                        */
+                       memmove(pt, bpt, ept - bpt);
+                       free(up);
+                       return (pt);
+               }
+
+               /*
+                * Build pointer to the parent directory, allocating memory
+                * as necessary.  Max length is 3 for "../", the largest
+                * possible component name, plus a trailing NULL.
+                */
+               if (bup + 3  + MAXNAMLEN + 1 >= eup) {
+                       char *nup;
+
+                       if ((nup = realloc(up, upsize *= 2)) == NULL)
+                               goto err;
+                       up = nup;
+                       bup = up;
+                       eup = up + upsize;
+               }
+               *bup++ = '.';
+               *bup++ = '.';
+               *bup = '\0';
+
+               /* Open and stat parent directory. 
+                * RACE?? - replaced fstat(dirfd(dir), &s) w/ lstat(up,&s) 
+                 */
+               if (!(dir = opendir(up)) || lstat(up,&s))
+                       goto err;
+
+               /* Add trailing slash for next directory. */
+               *bup++ = '/';
+
+               /*
+                * If it's a mount point, have to stat each element because
+                * the inode number in the directory is for the entry in the
+                * parent directory, not the inode number of the mounted file.
+                */
+               save_errno = 0;
+               if (s.st_dev == dev) {
+                       for (;;) {
+                               if (!(dp = readdir(dir)))
+                                       goto notfound;
+                               if (dp->d_fileno == ino)
+                                       break;
+                       }
+               } else
+                       for (;;) {
+                               if (!(dp = readdir(dir)))
+                                       goto notfound;
+                               if (ISDOT(dp))
+                                       continue;
+                               memmove(bup, dp->d_name, dp->d_namlen + 1);
+
+                               /* Save the first error for later. */
+                               if (lstat(up, &s)) {
+                                       if (!save_errno)
+                                               save_errno = errno;
+                                       errno = 0;
+                                       continue;
+                               }
+                               if (s.st_dev == dev && s.st_ino == ino)
+                                       break;
+                       }
+
+               /*
+                * Check for length of the current name, preceding slash,
+                * leading slash.
+                */
+               if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) {
+                       size_t len, off;
+                       char *npt;
+
+                       if (!ptsize) {
+                               errno = ERANGE;
+                               goto err;
+                       }
+                       off = bpt - pt;
+                       len = ept - bpt;
+                       if ((npt = realloc(pt, ptsize *= 2)) == NULL)
+                               goto err;
+                       pt = npt;
+                       bpt = pt + off;
+                       ept = pt + ptsize;
+                       memmove(ept - len, bpt, len);
+                       bpt = ept - len;
+               }
+               if (!first)
+                       *--bpt = '/';
+               bpt -= dp->d_namlen;
+               memmove(bpt, dp->d_name, dp->d_namlen);
+               (void)closedir(dir);
+
+               /* Truncate any file name. */
+               *bup = '\0';
+       }
+
+notfound:
+       /*
+        * If readdir set errno, use it, not any saved error; otherwise,
+        * didn't find the current directory in its parent directory, set
+        * errno to ENOENT.
+        */
+       if (!errno)
+               errno = save_errno ? save_errno : ENOENT;
+       /* FALLTHROUGH */
+err:
+       if (ptsize)
+               free(pt);
+       if (up)
+               free(up);
+       if (dir)
+               (void)closedir(dir);
+       return (NULL);
+}
+
+#endif /* !defined(HAVE_GETCWD) */
diff --git a/openssh/openbsd-compat/getcwd.h b/openssh/openbsd-compat/getcwd.h
new file mode 100644 (file)
index 0000000..bb41770
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_GETCWD_H 
+#define _BSD_GETCWD_H
+#include "config.h"
+
+#if !defined(HAVE_GETCWD)
+
+char *getcwd(char *pt, size_t size);
+
+#endif /* !defined(HAVE_GETCWD) */
+#endif /* _BSD_GETCWD_H */
diff --git a/openssh/openbsd-compat/getgrouplist.c b/openssh/openbsd-compat/getgrouplist.c
new file mode 100644 (file)
index 0000000..f7a27c3
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_GETGROUPLIST
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: getgrouplist.c,v 1.7 1997/08/19 19:13:27 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * get credential
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <grp.h>
+
+int
+getgrouplist(uname, agroup, groups, grpcnt)
+       const char *uname;
+       gid_t agroup;
+       register gid_t *groups;
+       int *grpcnt;
+{
+       register struct group *grp;
+       register int i, ngroups;
+       int ret, maxgroups;
+       int bail;
+
+       ret = 0;
+       ngroups = 0;
+       maxgroups = *grpcnt;
+
+       /*
+        * install primary group
+        */
+       if (ngroups >= maxgroups) {
+               *grpcnt = ngroups;
+               return (-1);
+       }
+       groups[ngroups++] = agroup;
+
+       /*
+        * Scan the group file to find additional groups.
+        */
+       setgrent();
+       while ((grp = getgrent())) {
+               if (grp->gr_gid == agroup)
+                       continue;
+               for (bail = 0, i = 0; bail == 0 && i < ngroups; i++)
+                       if (groups[i] == grp->gr_gid)
+                               bail = 1;
+               if (bail)
+                       continue;
+               for (i = 0; grp->gr_mem[i]; i++) {
+                       if (!strcmp(grp->gr_mem[i], uname)) {
+                               if (ngroups >= maxgroups) {
+                                       ret = -1;
+                                       goto out;
+                               }
+                               groups[ngroups++] = grp->gr_gid;
+                               break;
+                       }
+               }
+       }
+out:
+       endgrent();
+       *grpcnt = ngroups;
+       return (ret);
+}
+
+#endif /* HAVE_GETGROUPLIST */
diff --git a/openssh/openbsd-compat/getgrouplist.h b/openssh/openbsd-compat/getgrouplist.h
new file mode 100644 (file)
index 0000000..210dd41
--- /dev/null
@@ -0,0 +1,16 @@
+/* $Id$ */
+
+#ifndef _BSD_GETGROUPLIST_H
+#define _BSD_GETGROUPLIST_H
+
+#include "config.h"
+
+#ifndef HAVE_GETGROUPLIST
+
+#include <grp.h>
+
+int getgrouplist(const char *, gid_t, gid_t *, int *);
+
+#endif
+
+#endif
diff --git a/openssh/openbsd-compat/getopt.c b/openssh/openbsd-compat/getopt.c
new file mode 100644 (file)
index 0000000..9e13504
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: getopt.c,v 1.2 1996/08/19 08:33:32 tholo Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int    opterr = 1,             /* if error message should be printed */
+       optind = 1,             /* index into parent argv vector */
+       optopt,                 /* character checked for validity */
+       optreset;               /* reset getopt */
+char   *optarg;                /* argument associated with option */
+
+#define        BADCH   (int)'?'
+#define        BADARG  (int)':'
+#define        EMSG    ""
+
+/*
+ * getopt --
+ *     Parse argc/argv argument vector.
+ */
+int
+BSDgetopt(nargc, nargv, ostr)
+       int nargc;
+       char * const *nargv;
+       const char *ostr;
+{
+       extern char *__progname;
+       static char *place = EMSG;              /* option letter processing */
+       char *oli;                              /* option letter list index */
+
+       if (optreset || !*place) {              /* update scanning pointer */
+               optreset = 0;
+               if (optind >= nargc || *(place = nargv[optind]) != '-') {
+                       place = EMSG;
+                       return (-1);
+               }
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       ++optind;
+                       place = EMSG;
+                       return (-1);
+               }
+       }                                       /* option letter okay? */
+       if ((optopt = (int)*place++) == (int)':' ||
+           !(oli = strchr(ostr, optopt))) {
+               /*
+                * if the user didn't specify '-' as an option,
+                * assume it means -1.
+                */
+               if (optopt == (int)'-')
+                       return (-1);
+               if (!*place)
+                       ++optind;
+               if (opterr && *ostr != ':')
+                       (void)fprintf(stderr,
+                           "%s: illegal option -- %c\n", __progname, optopt);
+               return (BADCH);
+       }
+       if (*++oli != ':') {                    /* don't need argument */
+               optarg = NULL;
+               if (!*place)
+                       ++optind;
+       }
+       else {                                  /* need an argument */
+               if (*place)                     /* no white space */
+                       optarg = place;
+               else if (nargc <= ++optind) {   /* no arg */
+                       place = EMSG;
+                       if (*ostr == ':')
+                               return (BADARG);
+                       if (opterr)
+                               (void)fprintf(stderr,
+                                   "%s: option requires an argument -- %c\n",
+                                   __progname, optopt);
+                       return (BADCH);
+               }
+               else                            /* white space */
+                       optarg = nargv[optind];
+               place = EMSG;
+               ++optind;
+       }
+       return (optopt);                        /* dump back option letter */
+}
+
+#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */
diff --git a/openssh/openbsd-compat/getopt.h b/openssh/openbsd-compat/getopt.h
new file mode 100644 (file)
index 0000000..3f0f163
--- /dev/null
@@ -0,0 +1,14 @@
+/* $Id$ */
+
+#ifndef _BSDGETOPT_H
+#define _BSDGETOPT_H
+
+#include "config.h"
+
+#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
+
+int BSDgetopt(int argc, char * const *argv, const char *opts);
+
+#endif
+
+#endif /* _BSDGETOPT_H */
diff --git a/openssh/openbsd-compat/glob.c b/openssh/openbsd-compat/glob.c
new file mode 100644 (file)
index 0000000..365d433
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#include <ctype.h>
+
+static long
+get_arg_max(void)
+{
+#ifdef ARG_MAX
+       return(ARG_MAX);
+#elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX)
+       return(sysconf(_SC_ARG_MAX));
+#else
+       return(256); /* XXX: arbitrary */
+#endif
+}
+
+#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
+    !defined(GLOB_HAS_GL_MATCHC)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)glob.c     8.3 (Berkeley) 10/13/93";
+#else
+static char rcsid[] = "$OpenBSD: glob.c,v 1.16 2001/04/05 18:36:12 deraadt Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ *     Escaping convention: \ inhibits any special meaning the following
+ *     character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ *     Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ *     Same as GLOB_NOCHECK, but it will only append pattern if it did
+ *     not contain any magic characters.  [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ *     Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ *     expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ *     expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ *     Number of matches in the current invocation of glob.
+ */
+
+
+#define        DOLLAR          '$'
+#define        DOT             '.'
+#define        EOS             '\0'
+#define        LBRACKET        '['
+#define        NOT             '!'
+#define        QUESTION        '?'
+#define        QUOTE           '\\'
+#define        RANGE           '-'
+#define        RBRACKET        ']'
+#define        SEP             '/'
+#define        STAR            '*'
+#define        TILDE           '~'
+#define        UNDERSCORE      '_'
+#define        LBRACE          '{'
+#define        RBRACE          '}'
+#define        SLASH           '/'
+#define        COMMA           ','
+
+#ifndef DEBUG
+
+#define        M_QUOTE         0x8000
+#define        M_PROTECT       0x4000
+#define        M_MASK          0xffff
+#define        M_ASCII         0x00ff
+
+typedef u_short Char;
+
+#else
+
+#define        M_QUOTE         0x80
+#define        M_PROTECT       0x40
+#define        M_MASK          0xff
+#define        M_ASCII         0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define        CHAR(c)         ((Char)((c)&M_ASCII))
+#define        META(c)         ((Char)((c)|M_QUOTE))
+#define        M_ALL           META('*')
+#define        M_END           META(']')
+#define        M_NOT           META('!')
+#define        M_ONE           META('?')
+#define        M_RNG           META('-')
+#define        M_SET           META('[')
+#define        ismeta(c)       (((c)&M_QUOTE) != 0)
+
+
+static int      compare __P((const void *, const void *));
+static int      g_Ctoc __P((const Char *, char *, u_int));
+static int      g_lstat __P((Char *, struct stat *, glob_t *));
+static DIR     *g_opendir __P((Char *, glob_t *));
+static Char    *g_strchr __P((Char *, int));
+static int      g_stat __P((Char *, struct stat *, glob_t *));
+static int      glob0 __P((const Char *, glob_t *));
+static int      glob1 __P((Char *, Char *, glob_t *, size_t *));
+static int      glob2 __P((Char *, Char *, Char *, Char *, Char *, Char *,
+                   glob_t *, size_t *));
+static int      glob3 __P((Char *, Char *, Char *, Char *, Char *, Char *,
+                   Char *, Char *, glob_t *, size_t *));
+static int      globextend __P((const Char *, glob_t *, size_t *));
+static const Char *
+                globtilde __P((const Char *, Char *, size_t, glob_t *));
+static int      globexp1 __P((const Char *, glob_t *));
+static int      globexp2 __P((const Char *, const Char *, glob_t *, int *));
+static int      match __P((Char *, Char *, Char *));
+#ifdef DEBUG
+static void     qprintf __P((const char *, Char *));
+#endif
+
+int
+glob(pattern, flags, errfunc, pglob)
+       const char *pattern;
+       int flags, (*errfunc) __P((const char *, int));
+       glob_t *pglob;
+{
+       const u_char *patnext;
+       int c;
+       Char *bufnext, *bufend, patbuf[MAXPATHLEN];
+
+       patnext = (u_char *) pattern;
+       if (!(flags & GLOB_APPEND)) {
+               pglob->gl_pathc = 0;
+               pglob->gl_pathv = NULL;
+               if (!(flags & GLOB_DOOFFS))
+                       pglob->gl_offs = 0;
+       }
+       pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+       pglob->gl_errfunc = errfunc;
+       pglob->gl_matchc = 0;
+
+       bufnext = patbuf;
+       bufend = bufnext + MAXPATHLEN - 1;
+       if (flags & GLOB_NOESCAPE)
+               while (bufnext < bufend && (c = *patnext++) != EOS)
+                       *bufnext++ = c;
+       else {
+               /* Protect the quoted characters. */
+               while (bufnext < bufend && (c = *patnext++) != EOS)
+                       if (c == QUOTE) {
+                               if ((c = *patnext++) == EOS) {
+                                       c = QUOTE;
+                                       --patnext;
+                               }
+                               *bufnext++ = c | M_PROTECT;
+                       } else
+                               *bufnext++ = c;
+       }
+       *bufnext = EOS;
+
+       if (flags & GLOB_BRACE)
+               return globexp1(patbuf, pglob);
+       else
+               return glob0(patbuf, pglob);
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int
+globexp1(pattern, pglob)
+       const Char *pattern;
+       glob_t *pglob;
+{
+       const Char* ptr = pattern;
+       int rv;
+
+       /* Protect a single {}, for find(1), like csh */
+       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+               return glob0(pattern, pglob);
+
+       while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+               if (!globexp2(ptr, pattern, pglob, &rv))
+                       return rv;
+
+       return glob0(pattern, pglob);
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int
+globexp2(ptr, pattern, pglob, rv)
+       const Char *ptr, *pattern;
+       glob_t *pglob;
+       int *rv;
+{
+       int     i;
+       Char   *lm, *ls;
+       const Char *pe, *pm, *pl;
+       Char    patbuf[MAXPATHLEN];
+
+       /* copy part up to the brace */
+       for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+               ;
+       *lm = EOS;
+       ls = lm;
+
+       /* Find the balanced brace */
+       for (i = 0, pe = ++ptr; *pe; pe++)
+               if (*pe == LBRACKET) {
+                       /* Ignore everything between [] */
+                       for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+                               ;
+                       if (*pe == EOS) {
+                               /*
+                                * We could not find a matching RBRACKET.
+                                * Ignore and just look for RBRACE
+                                */
+                               pe = pm;
+                       }
+               } else if (*pe == LBRACE)
+                       i++;
+               else if (*pe == RBRACE) {
+                       if (i == 0)
+                               break;
+                       i--;
+               }
+
+       /* Non matching braces; just glob the pattern */
+       if (i != 0 || *pe == EOS) {
+               *rv = glob0(patbuf, pglob);
+               return 0;
+       }
+
+       for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
+               switch (*pm) {
+               case LBRACKET:
+                       /* Ignore everything between [] */
+                       for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+                               ;
+                       if (*pm == EOS) {
+                               /*
+                                * We could not find a matching RBRACKET.
+                                * Ignore and just look for RBRACE
+                                */
+                               pm = pl;
+                       }
+                       break;
+
+               case LBRACE:
+                       i++;
+                       break;
+
+               case RBRACE:
+                       if (i) {
+                               i--;
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case COMMA:
+                       if (i && *pm == COMMA)
+                               break;
+                       else {
+                               /* Append the current string */
+                               for (lm = ls; (pl < pm); *lm++ = *pl++)
+                                       ;
+
+                               /*
+                                * Append the rest of the pattern after the
+                                * closing brace
+                                */
+                               for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
+                                       ;
+
+                               /* Expand the current pattern */
+#ifdef DEBUG
+                               qprintf("globexp2:", patbuf);
+#endif
+                               *rv = globexp1(patbuf, pglob);
+
+                               /* move after the comma, to the next string */
+                               pl = pm + 1;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       *rv = 0;
+       return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(pattern, patbuf, patbuf_len, pglob)
+       const Char *pattern;
+       Char *patbuf;
+       size_t patbuf_len;
+       glob_t *pglob;
+{
+       struct passwd *pwd;
+       char *h;
+       const Char *p;
+       Char *b, *eb;
+
+       if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+               return pattern;
+
+       /* Copy up to the end of the string or / */
+       eb = &patbuf[patbuf_len - 1];
+       for (p = pattern + 1, h = (char *) patbuf;
+           h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+               ;
+
+       *h = EOS;
+
+#if 0
+       if (h == (char *)eb)
+               return what;
+#endif
+
+       if (((char *) patbuf)[0] == EOS) {
+               /*
+                * handle a plain ~ or ~/ by expanding $HOME
+                * first and then trying the password file
+                */
+#if 0
+               if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
+#endif
+               if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
+                       if ((pwd = getpwuid(getuid())) == NULL)
+                               return pattern;
+                       else
+                               h = pwd->pw_dir;
+               }
+       } else {
+               /*
+                * Expand a ~user
+                */
+               if ((pwd = getpwnam((char*) patbuf)) == NULL)
+                       return pattern;
+               else
+                       h = pwd->pw_dir;
+       }
+
+       /* Copy the home directory */
+       for (b = patbuf; b < eb && *h; *b++ = *h++)
+               ;
+
+       /* Append the rest of the pattern */
+       while (b < eb && (*b++ = *p++) != EOS)
+               ;
+       *b = EOS;
+
+       return patbuf;
+}
+
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested).  Returns 0
+ * if things went well, nonzero if errors occurred.  It is not an error
+ * to find no matches.
+ */
+static int
+glob0(pattern, pglob)
+       const Char *pattern;
+       glob_t *pglob;
+{
+       const Char *qpatnext;
+       int c, err, oldpathc;
+       Char *bufnext, patbuf[MAXPATHLEN];
+       size_t limit = 0;
+
+       qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+       oldpathc = pglob->gl_pathc;
+       bufnext = patbuf;
+
+       /* We don't need to check for buffer overflow any more. */
+       while ((c = *qpatnext++) != EOS) {
+               switch (c) {
+               case LBRACKET:
+                       c = *qpatnext;
+                       if (c == NOT)
+                               ++qpatnext;
+                       if (*qpatnext == EOS ||
+                           g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
+                               *bufnext++ = LBRACKET;
+                               if (c == NOT)
+                                       --qpatnext;
+                               break;
+                       }
+                       *bufnext++ = M_SET;
+                       if (c == NOT)
+                               *bufnext++ = M_NOT;
+                       c = *qpatnext++;
+                       do {
+                               *bufnext++ = CHAR(c);
+                               if (*qpatnext == RANGE &&
+                                   (c = qpatnext[1]) != RBRACKET) {
+                                       *bufnext++ = M_RNG;
+                                       *bufnext++ = CHAR(c);
+                                       qpatnext += 2;
+                               }
+                       } while ((c = *qpatnext++) != RBRACKET);
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       *bufnext++ = M_END;
+                       break;
+               case QUESTION:
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       *bufnext++ = M_ONE;
+                       break;
+               case STAR:
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       /* collapse adjacent stars to one,
+                        * to avoid exponential behavior
+                        */
+                       if (bufnext == patbuf || bufnext[-1] != M_ALL)
+                               *bufnext++ = M_ALL;
+                       break;
+               default:
+                       *bufnext++ = CHAR(c);
+                       break;
+               }
+       }
+       *bufnext = EOS;
+#ifdef DEBUG
+       qprintf("glob0:", patbuf);
+#endif
+
+       if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
+               return(err);
+
+       /*
+        * If there was no match we are going to append the pattern
+        * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+        * and the pattern did not contain any magic characters
+        * GLOB_NOMAGIC is there just for compatibility with csh.
+        */
+       if (pglob->gl_pathc == oldpathc) {
+               if ((pglob->gl_flags & GLOB_NOCHECK) ||
+                   ((pglob->gl_flags & GLOB_NOMAGIC) &&
+                   !(pglob->gl_flags & GLOB_MAGCHAR)))
+                       return(globextend(pattern, pglob, &limit));
+               else
+                       return(GLOB_NOMATCH);
+       }
+       if (!(pglob->gl_flags & GLOB_NOSORT))
+               qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+                   pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+       return(0);
+}
+
+static int
+compare(p, q)
+       const void *p, *q;
+{
+       return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(pattern, pattern_last, pglob, limitp)
+       Char *pattern, *pattern_last;
+       glob_t *pglob;
+       size_t *limitp;
+{
+       Char pathbuf[MAXPATHLEN];
+
+       /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+       if (*pattern == EOS)
+               return(0);
+       return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
+           pathbuf, pathbuf+MAXPATHLEN-1,
+           pattern, pattern_last, pglob, limitp));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
+    pattern_last, pglob, limitp)
+       Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
+       Char *pattern, *pattern_last;
+       glob_t *pglob;
+       size_t *limitp;
+{
+       struct stat sb;
+       Char *p, *q;
+       int anymeta;
+
+       /*
+        * Loop over pattern segments until end of pattern or until
+        * segment with meta character found.
+        */
+       for (anymeta = 0;;) {
+               if (*pattern == EOS) {          /* End of pattern? */
+                       *pathend = EOS;
+                       if (g_lstat(pathbuf, &sb, pglob))
+                               return(0);
+
+                       if (((pglob->gl_flags & GLOB_MARK) &&
+                           pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
+                           (S_ISLNK(sb.st_mode) &&
+                           (g_stat(pathbuf, &sb, pglob) == 0) &&
+                           S_ISDIR(sb.st_mode)))) {
+                               if (pathend+1 > pathend_last)
+                                       return (1);
+                               *pathend++ = SEP;
+                               *pathend = EOS;
+                       }
+                       ++pglob->gl_matchc;
+                       return(globextend(pathbuf, pglob, limitp));
+               }
+
+               /* Find end of next segment, copy tentatively to pathend. */
+               q = pathend;
+               p = pattern;
+               while (*p != EOS && *p != SEP) {
+                       if (ismeta(*p))
+                               anymeta = 1;
+                       if (q+1 > pathend_last)
+                               return (1);
+                       *q++ = *p++;
+               }
+
+               if (!anymeta) {         /* No expansion, do next segment. */
+                       pathend = q;
+                       pattern = p;
+                       while (*pattern == SEP) {
+                               if (pathend+1 > pathend_last)
+                                       return (1);
+                               *pathend++ = *pattern++;
+                       }
+               } else
+                       /* Need expansion, recurse. */
+                       return(glob3(pathbuf, pathbuf_last, pathend,
+                           pathend_last, pattern, pattern_last,
+                           p, pattern_last, pglob, limitp));
+       }
+       /* NOTREACHED */
+}
+
+static int
+glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
+    restpattern, restpattern_last, pglob, limitp)
+       Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
+       Char *pattern, *pattern_last, *restpattern, *restpattern_last;
+       glob_t *pglob;
+       size_t *limitp;
+{
+       register struct dirent *dp;
+       DIR *dirp;
+       int err;
+       char buf[MAXPATHLEN];
+
+       /*
+        * The readdirfunc declaration can't be prototyped, because it is
+        * assigned, below, to two functions which are prototyped in glob.h
+        * and dirent.h as taking pointers to differently typed opaque
+        * structures.
+        */
+       struct dirent *(*readdirfunc)();
+
+       if (pathend > pathend_last)
+               return (1);
+       *pathend = EOS;
+       errno = 0;
+
+       if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+               /* TODO: don't call for ENOENT or ENOTDIR? */
+               if (pglob->gl_errfunc) {
+                       if (g_Ctoc(pathbuf, buf, sizeof(buf)))
+                               return(GLOB_ABORTED);
+                       if (pglob->gl_errfunc(buf, errno) ||
+                           pglob->gl_flags & GLOB_ERR)
+                               return(GLOB_ABORTED);
+               }
+               return(0);
+       }
+
+       err = 0;
+
+       /* Search directory for matching names. */
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               readdirfunc = pglob->gl_readdir;
+       else
+               readdirfunc = readdir;
+       while ((dp = (*readdirfunc)(dirp))) {
+               register u_char *sc;
+               register Char *dc;
+
+               /* Initial DOT must be matched literally. */
+               if (dp->d_name[0] == DOT && *pattern != DOT)
+                       continue;
+               dc = pathend;
+               sc = (u_char *) dp->d_name;
+               while (dc < pathend_last && (*dc++ = *sc++) != EOS)
+                       ;
+               if (dc >= pathend_last) {
+                       *dc = EOS;
+                       err = 1;
+                       break;
+               }
+
+               if (!match(pathend, pattern, restpattern)) {
+                       *pathend = EOS;
+                       continue;
+               }
+               err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
+                   restpattern, restpattern_last, pglob, limitp);
+               if (err)
+                       break;
+       }
+
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               (*pglob->gl_closedir)(dirp);
+       else
+               closedir(dirp);
+       return(err);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ *     Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(path, pglob, limitp)
+       const Char *path;
+       glob_t *pglob;
+       size_t *limitp;
+{
+       register char **pathv;
+       register int i;
+       u_int newsize, len;
+       char *copy;
+       const Char *p;
+
+       newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+       pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
+           malloc(newsize);
+       if (pathv == NULL) {
+               if (pglob->gl_pathv) {
+                       free(pglob->gl_pathv);
+                       pglob->gl_pathv = NULL;
+               }
+               return(GLOB_NOSPACE);
+       }
+
+       if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+               /* first time around -- clear initial gl_offs items */
+               pathv += pglob->gl_offs;
+               for (i = pglob->gl_offs; --i >= 0; )
+                       *--pathv = NULL;
+       }
+       pglob->gl_pathv = pathv;
+
+       for (p = path; *p++;)
+               ;
+       len = (size_t)(p - path);
+       *limitp += len;
+       if ((copy = malloc(len)) != NULL) {
+               if (g_Ctoc(path, copy, len)) {
+                       free(copy);
+                       return(GLOB_NOSPACE);
+               }
+               pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+       }
+       pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+       if ((pglob->gl_flags & GLOB_LIMIT) &&
+           newsize + *limitp >= (u_int) get_arg_max()) {
+               errno = 0;
+               return(GLOB_NOSPACE);
+       }
+
+       return(copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames.  Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(name, pat, patend)
+       register Char *name, *pat, *patend;
+{
+       int ok, negate_range;
+       Char c, k;
+
+       while (pat < patend) {
+               c = *pat++;
+               switch (c & M_MASK) {
+               case M_ALL:
+                       if (pat == patend)
+                               return(1);
+                       do
+                           if (match(name, pat, patend))
+                                   return(1);
+                       while (*name++ != EOS)
+                               ;
+                       return(0);
+               case M_ONE:
+                       if (*name++ == EOS)
+                               return(0);
+                       break;
+               case M_SET:
+                       ok = 0;
+                       if ((k = *name++) == EOS)
+                               return(0);
+                       if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
+                               ++pat;
+                       while (((c = *pat++) & M_MASK) != M_END)
+                               if ((*pat & M_MASK) == M_RNG) {
+                                       if (c <= k && k <= pat[1])
+                                               ok = 1;
+                                       pat += 2;
+                               } else if (c == k)
+                                       ok = 1;
+                       if (ok == negate_range)
+                               return(0);
+                       break;
+               default:
+                       if (*name++ != c)
+                               return(0);
+                       break;
+               }
+       }
+       return(*name == EOS);
+}
+
+/* Free allocated data belonging to a glob_t structure. */
+void
+globfree(pglob)
+       glob_t *pglob;
+{
+       register int i;
+       register char **pp;
+
+       if (pglob->gl_pathv != NULL) {
+               pp = pglob->gl_pathv + pglob->gl_offs;
+               for (i = pglob->gl_pathc; i--; ++pp)
+                       if (*pp)
+                               free(*pp);
+               free(pglob->gl_pathv);
+               pglob->gl_pathv = NULL;
+       }
+}
+
+static DIR *
+g_opendir(str, pglob)
+       register Char *str;
+       glob_t *pglob;
+{
+       char buf[MAXPATHLEN];
+
+       if (!*str)
+               strcpy(buf, ".");
+       else {
+               if (g_Ctoc(str, buf, sizeof(buf)))
+                       return(NULL);
+       }
+
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_opendir)(buf));
+
+       return(opendir(buf));
+}
+
+static int
+g_lstat(fn, sb, pglob)
+       register Char *fn;
+       struct stat *sb;
+       glob_t *pglob;
+{
+       char buf[MAXPATHLEN];
+
+       if (g_Ctoc(fn, buf, sizeof(buf)))
+               return(-1);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_lstat)(buf, sb));
+       return(lstat(buf, sb));
+}
+
+static int
+g_stat(fn, sb, pglob)
+       register Char *fn;
+       struct stat *sb;
+       glob_t *pglob;
+{
+       char buf[MAXPATHLEN];
+
+       if (g_Ctoc(fn, buf, sizeof(buf)))
+               return(-1);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_stat)(buf, sb));
+       return(stat(buf, sb));
+}
+
+static Char *
+g_strchr(str, ch)
+       Char *str;
+       int ch;
+{
+       do {
+               if (*str == ch)
+                       return (str);
+       } while (*str++);
+       return (NULL);
+}
+
+static int
+g_Ctoc(str, buf, len)
+       register const Char *str;
+       char *buf;
+       u_int len;
+{
+
+       while (len--) {
+               if ((*buf++ = *str++) == EOS)
+                       return (0);
+       }
+       return (1);
+}
+
+#ifdef DEBUG
+static void
+qprintf(str, s)
+       const char *str;
+       register Char *s;
+{
+       register Char *p;
+
+       (void)printf("%s:\n", str);
+       for (p = s; *p; p++)
+               (void)printf("%c", CHAR(*p));
+       (void)printf("\n");
+       for (p = s; *p; p++)
+               (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+       (void)printf("\n");
+       for (p = s; *p; p++)
+               (void)printf("%c", ismeta(*p) ? '_' : ' ');
+       (void)printf("\n");
+}
+#endif
+
+#endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
+          !defined(GLOB_HAS_GL_MATCHC) */
+
diff --git a/openssh/openbsd-compat/glob.h b/openssh/openbsd-compat/glob.h
new file mode 100644 (file)
index 0000000..b4c8f7a
--- /dev/null
@@ -0,0 +1,101 @@
+/*     $OpenBSD: glob.h,v 1.5 2001/03/18 17:18:58 deraadt Exp $        */
+/*     $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $     */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)glob.h      8.1 (Berkeley) 6/2/93
+ */
+
+#if !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC) || \
+    !defined(GLOB_HAS_GL_MATCHC)
+
+#ifndef _GLOB_H_
+#define        _GLOB_H_
+
+struct stat;
+typedef struct {
+       int gl_pathc;           /* Count of total paths so far. */
+       int gl_matchc;          /* Count of paths matching pattern. */
+       int gl_offs;            /* Reserved at beginning of gl_pathv. */
+       int gl_flags;           /* Copy of flags parameter to glob. */
+       char **gl_pathv;        /* List of paths matching pattern. */
+                               /* Copy of errfunc parameter to glob. */
+       int (*gl_errfunc) __P((const char *, int));
+
+       /*
+        * Alternate filesystem access methods for glob; replacement
+        * versions of closedir(3), readdir(3), opendir(3), stat(2)
+        * and lstat(2).
+        */
+       void (*gl_closedir) __P((void *));
+       struct dirent *(*gl_readdir) __P((void *));     
+       void *(*gl_opendir) __P((const char *));
+       int (*gl_lstat) __P((const char *, struct stat *));
+       int (*gl_stat) __P((const char *, struct stat *));
+} glob_t;
+
+/* Flags */
+#define        GLOB_APPEND     0x0001  /* Append to output from previous call. */
+#define        GLOB_DOOFFS     0x0002  /* Use gl_offs. */
+#define        GLOB_ERR        0x0004  /* Return on error. */
+#define        GLOB_MARK       0x0008  /* Append / to matching directories. */
+#define        GLOB_NOCHECK    0x0010  /* Return pattern itself if nothing matches. */
+#define        GLOB_NOSORT     0x0020  /* Don't sort. */
+
+#define        GLOB_ALTDIRFUNC 0x0040  /* Use alternately specified directory funcs. */
+#define        GLOB_BRACE      0x0080  /* Expand braces ala csh. */
+#define        GLOB_MAGCHAR    0x0100  /* Pattern had globbing characters. */
+#define        GLOB_NOMAGIC    0x0200  /* GLOB_NOCHECK without magic chars (csh). */
+#define        GLOB_QUOTE      0x0400  /* Quote special chars with \. */
+#define        GLOB_TILDE      0x0800  /* Expand tilde names from the passwd file. */
+#define        GLOB_NOESCAPE   0x1000  /* Disable backslash escaping. */
+#define GLOB_LIMIT     0x2000  /* Limit pattern match output to ARG_MAX */
+
+/* Error values returned by glob(3) */
+#define        GLOB_NOSPACE    (-1)    /* Malloc call failed. */
+#define        GLOB_ABORTED    (-2)    /* Unignored error. */
+#define        GLOB_NOMATCH    (-3)    /* No match and GLOB_NOCHECK not set. */
+#define        GLOB_NOSYS      (-4)    /* Function not supported. */
+#define GLOB_ABEND     GLOB_ABORTED
+
+int    glob __P((const char *, int, int (*)(const char *, int), glob_t *));
+void   globfree __P((glob_t *));
+
+#endif /* !_GLOB_H_ */
+
+#endif /* !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC)  ||
+         !defined(GLOB_HAS_GL_MATCHC */
+
diff --git a/openssh/openbsd-compat/inet_aton.c b/openssh/openbsd-compat/inet_aton.c
new file mode 100644 (file)
index 0000000..18e31e7
--- /dev/null
@@ -0,0 +1,193 @@
+/*     $OpenBSD: inet_addr.c,v 1.6 1999/05/03 22:31:14 yanick Exp $    */
+
+/*
+ * ++Copyright++ 1983, 1990, 1993
+ * -
+ * Copyright (c) 1983, 1990, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * 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, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION 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.
+ * -
+ * --Copyright--
+ */
+
+#include "config.h"
+
+#if !defined(HAVE_INET_ATON)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)inet_addr.c        8.1 (Berkeley) 6/17/93";
+static char rcsid[] = "$From: inet_addr.c,v 8.5 1996/08/05 08:31:35 vixie Exp $";
+#else
+static char rcsid[] = "$OpenBSD: inet_addr.c,v 1.6 1999/05/03 22:31:14 yanick Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#if 0
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+in_addr_t
+inet_addr(cp)
+       register const char *cp;
+{
+       struct in_addr val;
+
+       if (inet_aton(cp, &val))
+               return (val.s_addr);
+       return (INADDR_NONE);
+}
+#endif
+
+/* 
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(const char *cp, struct in_addr *addr)
+{
+       register u_int32_t val;
+       register int base, n;
+       register char c;
+       unsigned int parts[4];
+       register unsigned int *pp = parts;
+
+       c = *cp;
+       for (;;) {
+               /*
+                * Collect number up to ``.''.
+                * Values are specified as for C:
+                * 0x=hex, 0=octal, isdigit=decimal.
+                */
+               if (!isdigit(c))
+                       return (0);
+               val = 0; base = 10;
+               if (c == '0') {
+                       c = *++cp;
+                       if (c == 'x' || c == 'X')
+                               base = 16, c = *++cp;
+                       else
+                               base = 8;
+               }
+               for (;;) {
+                       if (isascii(c) && isdigit(c)) {
+                               val = (val * base) + (c - '0');
+                               c = *++cp;
+                       } else if (base == 16 && isascii(c) && isxdigit(c)) {
+                               val = (val << 4) |
+                                       (c + 10 - (islower(c) ? 'a' : 'A'));
+                               c = *++cp;
+                       } else
+                               break;
+               }
+               if (c == '.') {
+                       /*
+                        * Internet format:
+                        *      a.b.c.d
+                        *      a.b.c   (with c treated as 16 bits)
+                        *      a.b     (with b treated as 24 bits)
+                        */
+                       if (pp >= parts + 3)
+                               return (0);
+                       *pp++ = val;
+                       c = *++cp;
+               } else
+                       break;
+       }
+       /*
+        * Check for trailing characters.
+        */
+       if (c != '\0' && (!isascii(c) || !isspace(c)))
+               return (0);
+       /*
+        * Concoct the address according to
+        * the number of parts specified.
+        */
+       n = pp - parts + 1;
+       switch (n) {
+
+       case 0:
+               return (0);             /* initial nondigit */
+
+       case 1:                         /* a -- 32 bits */
+               break;
+
+       case 2:                         /* a.b -- 8.24 bits */
+               if ((val > 0xffffff) || (parts[0] > 0xff))
+                       return (0);
+               val |= parts[0] << 24;
+               break;
+
+       case 3:                         /* a.b.c -- 8.8.16 bits */
+               if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
+                       return (0);
+               val |= (parts[0] << 24) | (parts[1] << 16);
+               break;
+
+       case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
+               if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
+                       return (0);
+               val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+               break;
+       }
+       if (addr)
+               addr->s_addr = htonl(val);
+       return (1);
+}
+
+#endif /* !defined(HAVE_INET_ATON) */
diff --git a/openssh/openbsd-compat/inet_aton.h b/openssh/openbsd-compat/inet_aton.h
new file mode 100644 (file)
index 0000000..4e4b9ac
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_INET_ATON_H
+#define _BSD_INET_ATON_H
+
+#include "config.h"
+
+#ifndef HAVE_INET_ATON
+int inet_aton(const char *cp, struct in_addr *addr);
+#endif /* HAVE_INET_ATON */
+
+#endif /* _BSD_INET_ATON_H */
diff --git a/openssh/openbsd-compat/inet_ntoa.c b/openssh/openbsd-compat/inet_ntoa.c
new file mode 100644 (file)
index 0000000..8a8b3c8
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: inet_ntoa.c,v 1.2 1996/08/19 08:29:16 tholo Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include "inet_ntoa.h"
+
+char *inet_ntoa(struct in_addr in)
+{
+       static char b[18];
+       register char *p;
+
+       p = (char *)&in;
+#define        UC(b)   (((int)b)&0xff)
+       (void)snprintf(b, sizeof(b),
+           "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
+       return (b);
+}
+
+#endif /* defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA) */
diff --git a/openssh/openbsd-compat/inet_ntoa.h b/openssh/openbsd-compat/inet_ntoa.h
new file mode 100644 (file)
index 0000000..c3a6bb9
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_INET_NTOA_H
+#define _BSD_INET_NTOA_H
+
+#include "config.h"
+
+#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA)
+char *inet_ntoa(struct in_addr in);
+#endif /* defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA) */
+
+#endif /* _BSD_INET_NTOA_H */
diff --git a/openssh/openbsd-compat/inet_ntop.c b/openssh/openbsd-compat/inet_ntop.c
new file mode 100644 (file)
index 0000000..2b8d31f
--- /dev/null
@@ -0,0 +1,213 @@
+/*     $OpenBSD: inet_ntop.c,v 1.1 1997/03/13 19:07:32 downsj Exp $    */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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 "config.h"
+
+#ifndef HAVE_INET_NTOP
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char rcsid[] = "$From: inet_ntop.c,v 8.7 1996/08/05 08:41:18 vixie Exp $";
+#else
+static char rcsid[] = "$OpenBSD: inet_ntop.c,v 1.1 1997/03/13 19:07:32 downsj Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "openbsd-compat/fake-socket.h"
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifndef HAVE_CYGWIN
+#include <arpa/nameser.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ   16   /* IPv6 T_AAAA */                 
+#endif
+
+#ifndef INT16SZ
+#define INT16SZ     2    /* for systems without 16-bit ints */
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
+static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *     convert a network format address to presentation format.
+ * return:
+ *     pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *     Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(af, src, dst, size)
+       int af;
+       const void *src;
+       char *dst;
+       size_t size;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_ntop4(src, dst, size));
+       case AF_INET6:
+               return (inet_ntop6(src, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *     format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ *     `dst' (as a const)
+ * notes:
+ *     (1) uses no statics
+ *     (2) takes a u_char* not an in_addr as input
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       static const char fmt[] = "%u.%u.%u.%u";
+       char tmp[sizeof "255.255.255.255"];
+
+       if (snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2],
+           src[3]) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       /*
+        * Note that int32_t and int16_t need only be "at least" large enough
+        * to contain a value of the specified size.  On some systems, like
+        * Crays, there is no such thing as an integer variable with 16 bits.
+        * Keep this in mind if you think this function should have been coded
+        * to use pointer overlays.  All the world's not a VAX.
+        */
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+       struct { int base, len; } best, cur;
+       u_int words[IN6ADDRSZ / INT16SZ];
+       int i;
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       memset(words, '\0', sizeof words);
+       for (i = 0; i < IN6ADDRSZ; i++)
+               words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+       best.base = -1;
+       cur.base = -1;
+       for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+               if (words[i] == 0) {
+                       if (cur.base == -1)
+                               cur.base = i, cur.len = 1;
+                       else
+                               cur.len++;
+               } else {
+                       if (cur.base != -1) {
+                               if (best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if (cur.base != -1) {
+               if (best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if (best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /*
+        * Format the result.
+        */
+       tp = tmp;
+       for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+               /* Are we inside the best run of 0x00's? */
+               if (best.base != -1 && i >= best.base &&
+                   i < (best.base + best.len)) {
+                       if (i == best.base)
+                               *tp++ = ':';
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0)
+                       *tp++ = ':';
+               /* Is this address an encapsulated IPv4? */
+               if (i == 6 && best.base == 0 &&
+                   (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+                       if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               snprintf(tp, sizeof(tmp - (tp - tmp)), "%x", words[i]);
+               tp += strlen(tp);
+       }
+       /* Was it a trailing run of 0x00's? */
+       if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+               *tp++ = ':';
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+       if ((size_t)(tp - tmp) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+
+#endif /* !HAVE_INET_NTOP */
diff --git a/openssh/openbsd-compat/inet_ntop.h b/openssh/openbsd-compat/inet_ntop.h
new file mode 100644 (file)
index 0000000..dc0eb99
--- /dev/null
@@ -0,0 +1,13 @@
+/* $Id$ */
+
+#ifndef _BSD_INET_NTOP_H
+#define _BSD_INET_NTOP_H
+
+#include "config.h"
+
+#ifndef HAVE_INET_NTOP
+const char *                 
+inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif /* !HAVE_INET_NTOP */
+
+#endif /* _BSD_INET_NTOP_H */
diff --git a/openssh/openbsd-compat/mktemp.c b/openssh/openbsd-compat/mktemp.c
new file mode 100644 (file)
index 0000000..9ed1bc8
--- /dev/null
@@ -0,0 +1,183 @@
+/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */
+/* Changes: Removed mktemp */
+
+/*
+ * Copyright (c) 1987, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_MKDTEMP
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: mktemp.c,v 1.13 1998/06/30 23:03:13 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_CYGWIN
+#define open binary_open
+extern int binary_open();
+#endif
+
+static int _gettemp(char *, int *, int, int);
+
+int
+mkstemps(path, slen)
+       char *path;
+       int slen;
+{
+       int fd;
+
+       return (_gettemp(path, &fd, 0, slen) ? fd : -1);
+}
+
+int
+mkstemp(path)
+       char *path;
+{
+       int fd;
+
+       return (_gettemp(path, &fd, 0, 0) ? fd : -1);
+}
+
+char *
+mkdtemp(path)
+       char *path;
+{
+       return(_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL);
+}
+
+static int
+_gettemp(path, doopen, domkdir, slen)
+       char *path;
+       register int *doopen;
+       int domkdir;
+       int slen;
+{
+       register char *start, *trv, *suffp;
+       struct stat sbuf;
+       int pid, rval;
+
+       if (doopen && domkdir) {
+               errno = EINVAL;
+               return(0);
+       }
+
+       for (trv = path; *trv; ++trv)
+               ;
+       trv -= slen;
+       suffp = trv;
+       --trv;
+       if (trv < path) {
+               errno = EINVAL;
+               return (0);
+       }
+       pid = getpid();
+       while (*trv == 'X' && pid != 0) {
+               *trv-- = (pid % 10) + '0';
+               pid /= 10;
+       }
+       while (*trv == 'X') {
+               char c;
+
+               pid = (arc4random() & 0xffff) % (26+26);
+               if (pid < 26)
+                       c = pid + 'A';
+               else
+                       c = (pid - 26) + 'a';
+               *trv-- = c;
+       }
+       start = trv + 1;
+
+       /*
+        * check the target directory; if you have six X's and it
+        * doesn't exist this runs for a *very* long time.
+        */
+       if (doopen || domkdir) {
+               for (;; --trv) {
+                       if (trv <= path)
+                               break;
+                       if (*trv == '/') {
+                               *trv = '\0';
+                               rval = stat(path, &sbuf);
+                               *trv = '/';
+                               if (rval != 0)
+                                       return(0);
+                               if (!S_ISDIR(sbuf.st_mode)) {
+                                       errno = ENOTDIR;
+                                       return(0);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       for (;;) {
+               if (doopen) {
+                       if ((*doopen =
+                           open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+                               return(1);
+                       if (errno != EEXIST)
+                               return(0);
+               } else if (domkdir) {
+                       if (mkdir(path, 0700) == 0)
+                               return(1);
+                       if (errno != EEXIST)
+                               return(0);
+               } else if (lstat(path, &sbuf))
+                       return(errno == ENOENT ? 1 : 0);
+
+               /* tricky little algorithm for backward compatibility */
+               for (trv = start;;) {
+                       if (!*trv)
+                               return (0);
+                       if (*trv == 'Z') {
+                               if (trv == suffp)
+                                       return (0);
+                               *trv++ = 'a';
+                       } else {
+                               if (isdigit(*trv))
+                                       *trv = 'a';
+                               else if (*trv == 'z')   /* inc from z to A */
+                                       *trv = 'A';
+                               else {
+                                       if (trv == suffp)
+                                               return (0);
+                                       ++*trv;
+                               }
+                               break;
+                       }
+               }
+       }
+       /*NOTREACHED*/
+}
+
+#endif /* !HAVE_MKDTEMP */
diff --git a/openssh/openbsd-compat/mktemp.h b/openssh/openbsd-compat/mktemp.h
new file mode 100644 (file)
index 0000000..f799387
--- /dev/null
@@ -0,0 +1,13 @@
+/* $Id$ */
+
+#ifndef _BSD_MKTEMP_H
+#define _BSD_MKTEMP_H
+
+#include "config.h"
+#ifndef HAVE_MKDTEMP
+int mkstemps(char *path, int slen);
+int mkstemp(char *path);
+char *mkdtemp(char *path);
+#endif /* !HAVE_MKDTEMP */
+
+#endif /* _BSD_MKTEMP_H */
diff --git a/openssh/openbsd-compat/openbsd-compat.h b/openssh/openbsd-compat/openbsd-compat.h
new file mode 100644 (file)
index 0000000..845d98f
--- /dev/null
@@ -0,0 +1,44 @@
+/* $Id$ */
+
+#ifndef _OPENBSD_H
+#define _OPENBSD_H
+
+#include "config.h"
+
+/* OpenBSD function replacements */
+#include "bindresvport.h"
+#include "getcwd.h"
+#include "realpath.h"
+#include "rresvport.h"
+#include "strlcpy.h"
+#include "strlcat.h"
+#include "strmode.h"
+#include "mktemp.h"
+#include "daemon.h"
+#include "dirname.h"
+#include "base64.h"
+#include "sigact.h"
+#include "inet_ntoa.h"
+#include "inet_ntop.h"
+#include "strsep.h"
+#include "setproctitle.h"
+#include "getgrouplist.h"
+#include "glob.h"
+#include "readpassphrase.h"
+#include "getopt.h"
+
+/* Home grown routines */
+#include "bsd-arc4random.h"
+#include "bsd-misc.h"
+#include "bsd-snprintf.h"
+#include "bsd-waitpid.h"
+
+/* rfc2553 socket API replacements */
+#include "fake-getaddrinfo.h"
+#include "fake-getnameinfo.h"
+#include "fake-socket.h"
+
+/* Routines for a single OS platform */
+#include "bsd-cray.h"
+
+#endif /* _OPENBSD_H */
diff --git a/openssh/openbsd-compat/readpassphrase.c b/openssh/openbsd-compat/readpassphrase.c
new file mode 100644 (file)
index 0000000..fdef158
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.5 2001/06/27 13:23:30 djm Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "includes.h"
+
+#ifndef HAVE_READPASSPHRASE
+
+#include <termios.h>
+#include <readpassphrase.h>
+
+#ifdef TCSASOFT
+# define _T_FLUSH      (TCSAFLUSH|TCSASOFT)
+#else
+# define _T_FLUSH      (TCSAFLUSH)
+#endif
+
+/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
+#if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
+#  define _POSIX_VDISABLE       VDISABLE
+#endif
+
+char *
+readpassphrase(prompt, buf, bufsiz, flags)
+       const char *prompt;
+       char *buf;
+       size_t bufsiz;
+       int flags;
+{
+       struct termios term;
+       char ch, *p, *end;
+#ifdef _POSIX_VDISABLE
+       u_char status;
+#endif
+       int echo, input, output;
+       sigset_t oset, nset;
+
+       /* I suppose we could alloc on demand in this case (XXX). */
+       if (bufsiz == 0) {
+               errno = EINVAL;
+               return(NULL);
+       }
+
+       /*
+        * Read and write to /dev/tty if available.  If not, read from
+        * stdin and write to stderr unless a tty is required.
+        */
+       if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
+               if (flags & RPP_REQUIRE_TTY) {
+                       errno = ENOTTY;
+                       return(NULL);
+               }
+               input = STDIN_FILENO;
+               output = STDERR_FILENO;
+       }
+
+       /*
+        * We block SIGINT and SIGTSTP so the terminal is not left
+        * in an inconsistent state (ie: no echo).  It would probably
+        * be better to simply catch these though.
+        */
+       sigemptyset(&nset);
+       sigaddset(&nset, SIGINT);
+       sigaddset(&nset, SIGTSTP);
+       (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+
+       /* Turn off echo if possible. */
+       echo = 0;
+#ifdef _POSIX_VDISABLE
+       status = _POSIX_VDISABLE;
+#endif
+       if (tcgetattr(input, &term) == 0) {
+               if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO)) {
+                       echo = 1;
+                       term.c_lflag &= ~ECHO;
+               }
+#ifdef VSTATUS
+               if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) {
+                       status = term.c_cc[VSTATUS];
+                       term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+               }
+#endif
+               (void)tcsetattr(input, _T_FLUSH, &term);
+       }
+       if (!(flags & RPP_ECHO_ON)) {
+               if (tcgetattr(input, &term) == 0 && (term.c_lflag & ECHO)) {
+                       echo = 1;
+                       term.c_lflag &= ~ECHO;
+                       (void)tcsetattr(input, _T_FLUSH, &term);
+               }
+       }
+
+       (void)write(output, prompt, strlen(prompt));
+       end = buf + bufsiz - 1;
+       for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) {
+               if (p < end) {
+                       if ((flags & RPP_SEVENBIT))
+                               ch &= 0x7f;
+                       if (isalpha(ch)) {
+                               if ((flags & RPP_FORCELOWER))
+                                       ch = tolower(ch);
+                               if ((flags & RPP_FORCEUPPER))
+                                       ch = toupper(ch);
+                       }
+                       *p++ = ch;
+               }
+       }
+       *p = '\0';
+#ifdef _POSIX_VDISABLE
+       if (echo || status != _POSIX_VDISABLE) {
+#else
+       if (echo) {
+#endif
+               if (echo) {
+                       (void)write(output, "\n", 1);
+                       term.c_lflag |= ECHO;
+               }
+#ifdef VSTATUS
+               if (status != _POSIX_VDISABLE)
+                       term.c_cc[VSTATUS] = status;
+#endif
+               (void)tcsetattr(input, _T_FLUSH, &term);
+       }
+       (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+       if (input != STDIN_FILENO)
+               (void)close(input);
+       return(buf);
+}
+#endif /* HAVE_READPASSPHRASE */
+
+#if 0
+char *
+getpass(prompt)
+        const char *prompt;
+{
+       static char buf[_PASSWORD_LEN + 1];
+
+       return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
+}
+#endif
diff --git a/openssh/openbsd-compat/readpassphrase.h b/openssh/openbsd-compat/readpassphrase.h
new file mode 100644 (file)
index 0000000..9077b6e
--- /dev/null
@@ -0,0 +1,48 @@
+/*     $OpenBSD: readpassphrase.h,v 1.1 2000/11/21 00:48:38 millert Exp $      */
+
+/*
+ * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _READPASSPHRASE_H_
+#define _READPASSPHRASE_H_
+
+#include "includes.h"
+
+#ifndef HAVE_READPASSPHRASE
+
+#define RPP_ECHO_OFF    0x00           /* Turn off echo (default). */
+#define RPP_ECHO_ON     0x01           /* Leave echo on. */
+#define RPP_REQUIRE_TTY 0x02           /* Fail if there is no tty. */
+#define RPP_FORCELOWER  0x04           /* Force input to lower case. */
+#define RPP_FORCEUPPER  0x08           /* Force input to upper case. */
+#define RPP_SEVENBIT    0x10           /* Strip the high bit from input. */
+
+char *readpassphrase(const char *, char *, size_t, int);
+
+#endif /* HAVE_READPASSPHRASE */
+
+#endif /* !_READPASSPHRASE_H_ */
diff --git a/openssh/openbsd-compat/realpath.c b/openssh/openbsd-compat/realpath.c
new file mode 100644 (file)
index 0000000..ec801d4
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: realpath.c,v 1.5 2001/06/27 00:58:56 lebel Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * MAXSYMLINKS
+ */
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 5
+#endif
+
+/*
+ * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
+ *
+ * Find the real name of path, by removing all ".", ".." and symlink
+ * components.  Returns (resolved) on success, or (NULL) on failure,
+ * in which case the path which caused trouble is left in (resolved).
+ */
+char *
+realpath(const char *path, char *resolved)
+{
+       struct stat sb;
+       int fd, n, rootd, serrno = 0;
+       char *p, *q, wbuf[MAXPATHLEN], start[MAXPATHLEN];
+       int symlinks = 0;
+
+       /* Save the starting point. */
+       getcwd(start,MAXPATHLEN);       
+       if ((fd = open(".", O_RDONLY)) < 0) {
+               (void)strcpy(resolved, ".");
+               return (NULL);
+       }
+       close(fd);
+
+       /*
+        * Find the dirname and basename from the path to be resolved.
+        * Change directory to the dirname component.
+        * lstat the basename part.
+        *     if it is a symlink, read in the value and loop.
+        *     if it is a directory, then change to that directory.
+        * get the current directory name and append the basename.
+        */
+       strlcpy(resolved, path, MAXPATHLEN);
+loop:
+       q = strrchr(resolved, '/');
+       if (q != NULL) {
+               p = q + 1;
+               if (q == resolved)
+                       q = "/";
+               else {
+                       do {
+                               --q;
+                       } while (q > resolved && *q == '/');
+                       q[1] = '\0';
+                       q = resolved;
+               }
+               if (chdir(q) < 0)
+                       goto err1;
+       } else
+               p = resolved;
+
+       /* Deal with the last component. */
+       if (lstat(p, &sb) == 0) {
+               if (S_ISLNK(sb.st_mode)) {
+                       if (++symlinks > MAXSYMLINKS) {
+                               serrno = ELOOP;
+                               goto err1;
+                       }
+                       n = readlink(p, resolved, MAXPATHLEN-1);
+                       if (n < 0)
+                               goto err1;
+                       resolved[n] = '\0';
+                       goto loop;
+               }
+               if (S_ISDIR(sb.st_mode)) {
+                       if (chdir(p) < 0)
+                               goto err1;
+                       p = "";
+               }
+       }
+
+       /*
+        * Save the last component name and get the full pathname of
+        * the current directory.
+        */
+       (void)strcpy(wbuf, p);
+       if (getcwd(resolved, MAXPATHLEN) == 0)
+               goto err1;
+
+       /*
+        * Join the two strings together, ensuring that the right thing
+        * happens if the last component is empty, or the dirname is root.
+        */
+       if (resolved[0] == '/' && resolved[1] == '\0')
+               rootd = 1;
+       else
+               rootd = 0;
+
+       if (*wbuf) {
+               if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
+                       serrno = ENAMETOOLONG;
+                       goto err1;
+               }
+               if (rootd == 0)
+                       (void)strcat(resolved, "/");
+               (void)strcat(resolved, wbuf);
+       }
+
+       /* Go back to where we came from. */
+       if (chdir(start) < 0) {
+               serrno = errno;
+               goto err2;
+       }
+       return (resolved);
+
+err1:  chdir(start);
+err2:  errno = serrno;
+       return (NULL);
+}
+#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */
diff --git a/openssh/openbsd-compat/realpath.h b/openssh/openbsd-compat/realpath.h
new file mode 100644 (file)
index 0000000..0a2445d
--- /dev/null
@@ -0,0 +1,13 @@
+/* $Id$ */
+
+#ifndef _BSD_REALPATH_H
+#define _BSD_REALPATH_H
+
+#include "config.h"
+
+#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
+
+char *realpath(const char *path, char *resolved);
+
+#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */
+#endif /* _BSD_REALPATH_H */
diff --git a/openssh/openbsd-compat/rresvport.c b/openssh/openbsd-compat/rresvport.c
new file mode 100644 (file)
index 0000000..44eac20
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1995, 1996, 1998 Theo de Raadt.  All rights reserved.
+ * Copyright (c) 1983, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ *     This product includes software developed by Theo de Raadt.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifndef HAVE_RRESVPORT_AF
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: rresvport.c,v 1.5 2000/01/26 03:43:20 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "includes.h"
+
+#if 0
+int
+rresvport(alport)
+       int *alport;
+{
+       return rresvport_af(alport, AF_INET);
+}
+#endif
+
+int 
+rresvport_af(int *alport, sa_family_t af)
+{
+       struct sockaddr_storage ss;
+       struct sockaddr *sa;
+       u_int16_t *portp;
+       int s;
+       socklen_t salen;
+
+       memset(&ss, '\0', sizeof ss);
+       sa = (struct sockaddr *)&ss;
+
+       switch (af) {
+       case AF_INET:
+               salen = sizeof(struct sockaddr_in);
+               portp = &((struct sockaddr_in *)sa)->sin_port;
+               break;
+       case AF_INET6:
+               salen = sizeof(struct sockaddr_in6);
+               portp = &((struct sockaddr_in6 *)sa)->sin6_port;
+               break;
+       default:
+               errno = EPFNOSUPPORT;
+               return (-1);
+       }
+       sa->sa_family = af;
+       
+       s = socket(af, SOCK_STREAM, 0);
+       if (s < 0)
+               return (-1);
+
+       *portp = htons(*alport);
+       if (*alport < IPPORT_RESERVED - 1) {
+               if (bind(s, sa, salen) >= 0)
+                       return (s);
+               if (errno != EADDRINUSE) {
+                       (void)close(s);
+                       return (-1);
+               }
+       }
+
+       *portp = 0;
+       sa->sa_family = af;
+       if (bindresvport_sa(s, sa) == -1) {
+               (void)close(s);
+               return (-1);
+       }
+       *alport = ntohs(*portp);
+       return (s);
+}
+
+#endif /* HAVE_RRESVPORT_AF */
diff --git a/openssh/openbsd-compat/rresvport.h b/openssh/openbsd-compat/rresvport.h
new file mode 100644 (file)
index 0000000..cd908e1
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_RRESVPORT_H
+#define _BSD_RRESVPORT_H
+
+#include "config.h"
+
+#ifndef HAVE_RRESVPORT_AF
+int rresvport_af(int *alport, sa_family_t af);
+#endif /* !HAVE_RRESVPORT_AF */
+
+#endif /* _BSD_RRESVPORT_H */
diff --git a/openssh/openbsd-compat/setenv.c b/openssh/openbsd-compat/setenv.c
new file mode 100644 (file)
index 0000000..ac9670b
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#ifndef HAVE_SETENV
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: setenv.c,v 1.3 1998/02/02 22:44:53 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * __findenv --
+ *     Returns pointer to value associated with name, if any, else NULL.
+ *     Sets offset to be the offset of the name/value combination in the
+ *     environmental array, for use by setenv(3) and unsetenv(3).
+ *     Explicitly removes '=' in argument name.
+ *
+ *     This routine *should* be a static; don't use it.
+ */
+char *
+__findenv(name, offset)
+       register const char *name;
+       int *offset;
+{
+       extern char **environ;
+       register int len, i;
+       register const char *np;
+       register char **p, *cp;
+
+       if (name == NULL || environ == NULL)
+               return (NULL);
+       for (np = name; *np && *np != '='; ++np)
+               ;
+       len = np - name;
+       for (p = environ; (cp = *p) != NULL; ++p) {
+               for (np = name, i = len; i && *cp; i--)
+                       if (*cp++ != *np++)
+                               break;
+               if (i == 0 && *cp++ == '=') {
+                       *offset = p - environ;
+                       return (cp);
+               }
+       }
+       return (NULL);
+}
+
+/*
+ * setenv --
+ *     Set the value of the environmental variable "name" to be
+ *     "value".  If rewrite is set, replace any current value.
+ */
+int
+setenv(name, value, rewrite)
+       register const char *name;
+       register const char *value;
+       int rewrite;
+{
+       extern char **environ;
+       static int alloced;                     /* if allocated space before */
+       register char *C;
+       int l_value, offset;
+       char *__findenv();
+
+       if (*value == '=')                      /* no `=' in value */
+               ++value;
+       l_value = strlen(value);
+       if ((C = __findenv(name, &offset))) {   /* find if already exists */
+               if (!rewrite)
+                       return (0);
+               if (strlen(C) >= l_value) {     /* old larger; copy over */
+                       while ((*C++ = *value++));
+                       return (0);
+               }
+       } else {                                        /* create new slot */
+               register int    cnt;
+               register char   **P;
+
+               for (P = environ, cnt = 0; *P; ++P, ++cnt);
+               if (alloced) {                  /* just increase size */
+                       P = (char **)realloc((void *)environ,
+                           (size_t)(sizeof(char *) * (cnt + 2)));
+                       if (!P)
+                               return (-1);
+                       environ = P;
+               }
+               else {                          /* get new space */
+                       alloced = 1;            /* copy old entries into it */
+                       P = (char **)malloc((size_t)(sizeof(char *) *
+                           (cnt + 2)));
+                       if (!P)
+                               return (-1);
+                       memmove(P, environ, cnt * sizeof(char *));
+                       environ = P;
+               }
+               environ[cnt + 1] = NULL;
+               offset = cnt;
+       }
+       for (C = (char *)name; *C && *C != '='; ++C);   /* no `=' in name */
+       if (!(environ[offset] =                 /* name + `=' + value */
+           malloc((size_t)((int)(C - name) + l_value + 2))))
+               return (-1);
+       for (C = environ[offset]; (*C = *name++) && *C != '='; ++C)
+               ;
+       for (*C++ = '='; (*C++ = *value++); )
+               ;
+       return (0);
+}
+
+/*
+ * unsetenv(name) --
+ *     Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+       const char      *name;
+{
+       extern char **environ;
+       register char **P;
+       int offset;
+       char *__findenv();
+
+       while (__findenv(name, &offset))                /* if set multiple times */
+               for (P = &environ[offset];; ++P)
+                       if (!(*P = *(P + 1)))
+                               break;
+}
+
+#endif /* HAVE_SETENV */
diff --git a/openssh/openbsd-compat/setenv.h b/openssh/openbsd-compat/setenv.h
new file mode 100644 (file)
index 0000000..b938054
--- /dev/null
@@ -0,0 +1,14 @@
+/* $Id$ */
+
+#ifndef _BSD_SETENV_H
+#define _BSD_SETENV_H
+
+#include "config.h"
+
+#ifndef HAVE_SETENV
+
+int setenv(register const char *name, register const char *value, int rewrite);
+
+#endif /* !HAVE_SETENV */
+
+#endif /* _BSD_SETENV_H */
diff --git a/openssh/openbsd-compat/setproctitle.c b/openssh/openbsd-compat/setproctitle.c
new file mode 100644 (file)
index 0000000..38eca9a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Modified for OpenSSH by Kevin Steves
+ * October 2000
+ */
+
+/*
+ * Copyright (c) 1994, 1995 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christopher G. Demetriou
+ *     for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: setproctitle.c,v 1.7 1999/02/25 22:10:12 art Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "includes.h"
+
+#ifndef HAVE_SETPROCTITLE
+
+#define SPT_NONE       0
+#define SPT_PSTAT      1
+
+#ifndef SPT_TYPE
+#define SPT_TYPE       SPT_NONE
+#endif
+
+#if SPT_TYPE == SPT_PSTAT
+#include <sys/param.h>
+#include <sys/pstat.h>
+#endif /* SPT_TYPE == SPT_PSTAT */
+
+#define        MAX_PROCTITLE   2048
+
+extern char *__progname;
+
+/*
+ * Set Process Title (SPT) defines.  Modeled after sendmail's
+ * SPT type definition strategy.
+ *
+ * SPT_TYPE:
+ *
+ * SPT_NONE:   Don't set the process title.  Default.
+ * SPT_PSTAT:  Use pstat(PSTAT_SETCMD).  HP-UX specific.
+ */
+
+void
+setproctitle(const char *fmt, ...)
+{
+#if SPT_TYPE != SPT_NONE
+       va_list ap;
+       
+       char buf[MAX_PROCTITLE];
+       size_t used;
+
+#if SPT_TYPE == SPT_PSTAT
+       union pstun pst;
+#endif /* SPT_TYPE == SPT_PSTAT */
+
+       va_start(ap, fmt);
+       if (fmt != NULL) {
+               used = snprintf(buf, MAX_PROCTITLE, "%s: ", __progname);
+               if (used >= MAX_PROCTITLE)
+                       used = MAX_PROCTITLE - 1;
+               (void)vsnprintf(buf + used, MAX_PROCTITLE - used, fmt, ap);
+       } else
+               (void)snprintf(buf, MAX_PROCTITLE, "%s", __progname);
+       va_end(ap);
+       used = strlen(buf);
+
+#if SPT_TYPE == SPT_PSTAT
+       pst.pst_command = buf;
+       pstat(PSTAT_SETCMD, pst, used, 0, 0);
+#endif /* SPT_TYPE == SPT_PSTAT */
+
+#endif /* SPT_TYPE != SPT_NONE */
+}
+#endif /* HAVE_SETPROCTITLE */
diff --git a/openssh/openbsd-compat/setproctitle.h b/openssh/openbsd-compat/setproctitle.h
new file mode 100644 (file)
index 0000000..73ae9f9
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_SETPROCTITLE_H
+#define _BSD_SETPROCTITLE_H
+
+#include "config.h"
+
+#ifndef HAVE_SETPROCTITLE
+void setproctitle(const char *fmt, ...);
+#endif
+
+#endif /* _BSD_SETPROCTITLE_H */
diff --git a/openssh/openbsd-compat/sigact.c b/openssh/openbsd-compat/sigact.c
new file mode 100644 (file)
index 0000000..806eb02
--- /dev/null
@@ -0,0 +1,102 @@
+/*     $OpenBSD: sigaction.c,v 1.3 1999/06/27 08:14:21 millert Exp $   */
+
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc.                        *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+
+/****************************************************************************
+ *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
+ *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
+ ****************************************************************************/
+
+#include "config.h"
+#include <signal.h>
+#include "sigact.h"
+
+/* This file provides sigaction() emulation using sigvec() */
+/* Use only if this is non POSIX system */
+
+#if !HAVE_SIGACTION && HAVE_SIGVEC
+
+int
+sigaction(int sig, struct sigaction *sigact, struct sigaction *osigact)
+{
+       return sigvec(sig, &(sigact->sv), &(osigact->sv));
+}
+
+int
+sigemptyset (sigset_t * mask)
+{
+       *mask = 0;
+       return 0;
+}
+
+int
+sigprocmask (int mode, sigset_t * mask, sigset_t * omask)
+{
+       sigset_t current = sigsetmask(0);
+
+       if (omask) *omask = current;
+
+       if (mode==SIG_BLOCK)
+               current |= *mask;
+       else if (mode==SIG_UNBLOCK)
+               current &= ~*mask;
+       else if (mode==SIG_SETMASK)
+       current = *mask;
+
+       sigsetmask(current);
+       return 0;
+}
+
+int
+sigsuspend (sigset_t * mask)
+{
+       return sigpause(*mask);
+}
+
+int
+sigdelset (sigset_t * mask, int sig)
+{
+       *mask &= ~sigmask(sig);
+       return 0;
+}
+
+int
+sigaddset (sigset_t * mask, int sig)
+{
+       *mask |= sigmask(sig);
+       return 0;
+}
+
+int
+sigismember (sigset_t * mask, int sig)
+{
+       return (*mask & sigmask(sig)) != 0;
+}
+
+#endif
diff --git a/openssh/openbsd-compat/sigact.h b/openssh/openbsd-compat/sigact.h
new file mode 100644 (file)
index 0000000..b37c1f8
--- /dev/null
@@ -0,0 +1,88 @@
+/*     $OpenBSD: SigAction.h,v 1.2 1999/06/27 08:15:19 millert Exp $   */
+
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc.                        *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+
+/****************************************************************************
+ *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
+ *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
+ ****************************************************************************/
+
+/*
+ * $From: SigAction.h,v 1.5 1999/06/19 23:00:54 tom Exp $
+ *
+ * This file exists to handle non-POSIX systems which don't have <unistd.h>,
+ * and usually no sigaction() nor <termios.h>
+ */
+
+#ifndef _SIGACTION_H
+#define _SIGACTION_H
+
+#if !defined(HAVE_SIGACTION) && defined(HAVE_SIGVEC)
+
+#undef  SIG_BLOCK
+#define SIG_BLOCK       00
+
+#undef  SIG_UNBLOCK
+#define SIG_UNBLOCK     01
+
+#undef  SIG_SETMASK
+#define SIG_SETMASK     02
+
+/*
+ * <bsd/signal.h> is in the Linux 1.2.8 + gcc 2.7.0 configuration,
+ * and is useful for testing this header file.
+ */
+#if HAVE_BSD_SIGNAL_H
+# include <bsd/signal.h>
+#endif
+
+struct sigaction
+{
+       struct sigvec sv;
+};
+
+typedef unsigned long sigset_t;
+
+#undef  sa_mask
+#define sa_mask sv.sv_mask
+#undef  sa_handler
+#define sa_handler sv.sv_handler
+#undef  sa_flags
+#define sa_flags sv.sv_flags
+
+int sigaction(int sig, struct sigaction *sigact, struct sigaction *osigact);
+int sigprocmask (int how, sigset_t *mask, sigset_t *omask);
+int sigemptyset (sigset_t *mask);
+int sigsuspend (sigset_t *mask);
+int sigdelset (sigset_t *mask, int sig);
+int sigaddset (sigset_t *mask, int sig);
+
+#endif /* !defined(HAVE_SIGACTION) && defined(HAVE_SIGVEC) */
+
+#endif /* !defined(_SIGACTION_H) */
diff --git a/openssh/openbsd-compat/strlcat.c b/openssh/openbsd-compat/strlcat.c
new file mode 100644 (file)
index 0000000..6ff65c1
--- /dev/null
@@ -0,0 +1,79 @@
+/*     $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $     */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#ifndef HAVE_STRLCAT
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+#include "strlcat.h"
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(dst, src, siz)
+       char *dst;
+       const char *src;
+       size_t siz;
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return(dlen + strlen(s));
+       while (*s != '\0') {
+               if (n != 1) {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+
+       return(dlen + (s - src));       /* count does not include NUL */
+}
+
+#endif /* !HAVE_STRLCAT */
diff --git a/openssh/openbsd-compat/strlcat.h b/openssh/openbsd-compat/strlcat.h
new file mode 100644 (file)
index 0000000..02fbc39
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_STRLCAT_H
+#define _BSD_STRLCAT_H
+
+#include "config.h"
+#ifndef HAVE_STRLCAT
+#include <sys/types.h>
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif /* !HAVE_STRLCAT */
+
+#endif /* _BSD_STRLCAT_H */
diff --git a/openssh/openbsd-compat/strlcpy.c b/openssh/openbsd-compat/strlcpy.c
new file mode 100644 (file)
index 0000000..b5e5a55
--- /dev/null
@@ -0,0 +1,75 @@
+/*     $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $     */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#ifndef HAVE_STRLCPY
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+#include "strlcpy.h"
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(dst, src, siz)
+       char *dst;
+       const char *src;
+       size_t siz;
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0) {
+               if (siz != 0)
+                       *d = '\0';              /* NUL-terminate dst */
+               while (*s++)
+                       ;
+       }
+
+       return(s - src - 1);    /* count does not include NUL */
+}
+
+#endif /* !HAVE_STRLCPY */
diff --git a/openssh/openbsd-compat/strlcpy.h b/openssh/openbsd-compat/strlcpy.h
new file mode 100644 (file)
index 0000000..7b33e4f
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_STRLCPY_H
+#define _BSD_STRLCPY_H
+
+#include "config.h"
+#ifndef HAVE_STRLCPY
+#include <sys/types.h>
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif /* !HAVE_STRLCPY */
+
+#endif /* _BSD_STRLCPY_H */
diff --git a/openssh/openbsd-compat/strmode.c b/openssh/openbsd-compat/strmode.c
new file mode 100644 (file)
index 0000000..e64d198
--- /dev/null
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#ifndef HAVE_STRMODE
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strmode.c,v 1.3 1997/06/13 13:57:20 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+void
+strmode(register mode_t mode, register char *p)
+{
+        /* print type */
+       switch (mode & S_IFMT) {
+       case S_IFDIR:                   /* directory */
+               *p++ = 'd';
+               break;
+       case S_IFCHR:                   /* character special */
+               *p++ = 'c';
+               break;
+       case S_IFBLK:                   /* block special */
+               *p++ = 'b';
+               break;
+       case S_IFREG:                   /* regular */
+               *p++ = '-';
+               break;
+       case S_IFLNK:                   /* symbolic link */
+               *p++ = 'l';
+               break;
+#ifdef S_IFSOCK
+       case S_IFSOCK:                  /* socket */
+               *p++ = 's';
+               break;
+#endif
+#ifdef S_IFIFO
+       case S_IFIFO:                   /* fifo */
+               *p++ = 'p';
+               break;
+#endif
+#ifdef S_IFWHT
+       case S_IFWHT:                   /* whiteout */
+               *p++ = 'w';
+               break;
+#endif
+       default:                        /* unknown */
+               *p++ = '?';
+               break;
+       }
+       /* usr */
+       if (mode & S_IRUSR)
+               *p++ = 'r';
+       else
+               *p++ = '-';
+       if (mode & S_IWUSR)
+               *p++ = 'w';
+       else
+               *p++ = '-';
+       switch (mode & (S_IXUSR | S_ISUID)) {
+       case 0:
+               *p++ = '-';
+               break;
+       case S_IXUSR:
+               *p++ = 'x';
+               break;
+       case S_ISUID:
+               *p++ = 'S';
+               break;
+       case S_IXUSR | S_ISUID:
+               *p++ = 's';
+               break;
+       }
+       /* group */
+       if (mode & S_IRGRP)
+               *p++ = 'r';
+       else
+               *p++ = '-';
+       if (mode & S_IWGRP)
+               *p++ = 'w';
+       else
+               *p++ = '-';
+       switch (mode & (S_IXGRP | S_ISGID)) {
+       case 0:
+               *p++ = '-';
+               break;
+       case S_IXGRP:
+               *p++ = 'x';
+               break;
+       case S_ISGID:
+               *p++ = 'S';
+               break;
+       case S_IXGRP | S_ISGID:
+               *p++ = 's';
+               break;
+       }
+       /* other */
+       if (mode & S_IROTH)
+               *p++ = 'r';
+       else
+               *p++ = '-';
+       if (mode & S_IWOTH)
+               *p++ = 'w';
+       else
+               *p++ = '-';
+       switch (mode & (S_IXOTH | S_ISVTX)) {
+       case 0:
+               *p++ = '-';
+               break;
+       case S_IXOTH:
+               *p++ = 'x';
+               break;
+       case S_ISVTX:
+               *p++ = 'T';
+               break;
+       case S_IXOTH | S_ISVTX:
+               *p++ = 't';
+               break;
+       }
+       *p++ = ' ';             /* will be a '+' if ACL's implemented */
+       *p = '\0';
+}
+#endif
diff --git a/openssh/openbsd-compat/strmode.h b/openssh/openbsd-compat/strmode.h
new file mode 100644 (file)
index 0000000..9166379
--- /dev/null
@@ -0,0 +1,7 @@
+/* $Id$ */
+
+#ifndef HAVE_STRMODE
+
+void strmode(register mode_t mode, register char *p);
+
+#endif
diff --git a/openssh/openbsd-compat/strsep.c b/openssh/openbsd-compat/strsep.c
new file mode 100644 (file)
index 0000000..c03649c
--- /dev/null
@@ -0,0 +1,89 @@
+/*     $OpenBSD: strsep.c,v 1.3 1997/08/20 04:28:14 millert Exp $      */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if !defined(HAVE_STRSEP)
+
+#include <string.h>
+#include <stdio.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)strsep.c   8.1 (Berkeley) 6/4/93";
+#else
+static char *rcsid = "$OpenBSD: strsep.c,v 1.3 1997/08/20 04:28:14 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.  
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+       register char *s;
+       register const char *spanp;
+       register int c, sc;
+       char *tok;
+
+       if ((s = *stringp) == NULL)
+               return (NULL);
+       for (tok = s;;) {
+               c = *s++;
+               spanp = delim;
+               do {
+                       if ((sc = *spanp++) == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else
+                                       s[-1] = 0;
+                               *stringp = s;
+                               return (tok);
+                       }
+               } while (sc != 0);
+       }
+       /* NOTREACHED */
+}
+
+#endif /* !defined(HAVE_STRSEP) */
diff --git a/openssh/openbsd-compat/strsep.h b/openssh/openbsd-compat/strsep.h
new file mode 100644 (file)
index 0000000..9e54e05
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+#ifndef _BSD_STRSEP_H
+#define _BSD_STRSEP_H
+
+#include "config.h"
+
+#ifndef HAVE_STRSEP
+char *strsep(char **stringp, const char *delim);
+#endif /* HAVE_STRSEP */
+
+#endif /* _BSD_STRSEP_H */
diff --git a/openssh/packet.c b/openssh/packet.c
new file mode 100644 (file)
index 0000000..7b94169
--- /dev/null
@@ -0,0 +1,1286 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file contains code implementing the packet protocol and communication
+ * with the other side.  This same code is used both on client and server side.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * SSH2 packet format added by Markus Friedl.
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: packet.c,v 1.72 2001/11/10 13:37:20 markus Exp $");
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "packet.h"
+#include "bufaux.h"
+#include "crc32.h"
+#include "getput.h"
+
+#include "compress.h"
+#include "deattack.h"
+#include "channels.h"
+
+#include "compat.h"
+#include "ssh1.h"
+#include "ssh2.h"
+
+#include "cipher.h"
+#include "kex.h"
+#include "mac.h"
+#include "log.h"
+#include "canohost.h"
+
+#ifdef PACKET_DEBUG
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+/*
+ * This variable contains the file descriptors used for communicating with
+ * the other side.  connection_in is used for reading; connection_out for
+ * writing.  These can be the same descriptor, in which case it is assumed to
+ * be a socket.
+ */
+static int connection_in = -1;
+static int connection_out = -1;
+
+/* Protocol flags for the remote side. */
+static u_int remote_protocol_flags = 0;
+
+/* Encryption context for receiving data.  This is only used for decryption. */
+static CipherContext receive_context;
+
+/* Encryption context for sending data.  This is only used for encryption. */
+static CipherContext send_context;
+
+/* Buffer for raw input data from the socket. */
+static Buffer input;
+
+/* Buffer for raw output data going to the socket. */
+static Buffer output;
+
+/* Buffer for the partial outgoing packet being constructed. */
+static Buffer outgoing_packet;
+
+/* Buffer for the incoming packet currently being processed. */
+static Buffer incoming_packet;
+
+/* Scratch buffer for packet compression/decompression. */
+static Buffer compression_buffer;
+static int compression_buffer_ready = 0;
+
+/* Flag indicating whether packet compression/decompression is enabled. */
+static int packet_compression = 0;
+
+/* default maximum packet size */
+int max_packet_size = 32768;
+
+/* Flag indicating whether this module has been initialized. */
+static int initialized = 0;
+
+/* Set to true if the connection is interactive. */
+static int interactive_mode = 0;
+
+/* Session key information for Encryption and MAC */
+Newkeys *newkeys[MODE_MAX];
+
+/* roundup current message to extra_pad bytes */
+static u_char extra_pad = 0;
+
+/*
+ * Sets the descriptors used for communication.  Disables encryption until
+ * packet_set_encryption_key is called.
+ */
+void
+packet_set_connection(int fd_in, int fd_out)
+{
+       Cipher *none = cipher_by_name("none");
+       if (none == NULL)
+               fatal("packet_set_connection: cannot load cipher 'none'");
+       connection_in = fd_in;
+       connection_out = fd_out;
+       cipher_init(&send_context, none, (u_char *) "", 0, NULL, 0);
+       cipher_init(&receive_context, none, (u_char *) "", 0, NULL, 0);
+       newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
+       if (!initialized) {
+               initialized = 1;
+               buffer_init(&input);
+               buffer_init(&output);
+               buffer_init(&outgoing_packet);
+               buffer_init(&incoming_packet);
+       }
+       /* Kludge: arrange the close function to be called from fatal(). */
+       fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
+}
+
+/* Returns 1 if remote host is connected via socket, 0 if not. */
+
+int
+packet_connection_is_on_socket()
+{
+       struct sockaddr_storage from, to;
+       socklen_t fromlen, tolen;
+
+       /* filedescriptors in and out are the same, so it's a socket */
+       if (connection_in == connection_out)
+               return 1;
+       fromlen = sizeof(from);
+       memset(&from, 0, sizeof(from));
+       if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0)
+               return 0;
+       tolen = sizeof(to);
+       memset(&to, 0, sizeof(to));
+       if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0)
+               return 0;
+       if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
+               return 0;
+       if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
+               return 0;
+       return 1;
+}
+
+/* returns 1 if connection is via ipv4 */
+
+int
+packet_connection_is_ipv4()
+{
+       struct sockaddr_storage to;
+       socklen_t tolen = sizeof(to);
+
+       memset(&to, 0, sizeof(to));
+       if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
+               return 0;
+       if (to.ss_family != AF_INET)
+               return 0;
+       return 1;
+}
+
+/* Sets the connection into non-blocking mode. */
+
+void
+packet_set_nonblocking()
+{
+       /* Set the socket into non-blocking mode. */
+       if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
+               error("fcntl O_NONBLOCK: %.100s", strerror(errno));
+
+       if (connection_out != connection_in) {
+               if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
+                       error("fcntl O_NONBLOCK: %.100s", strerror(errno));
+       }
+}
+
+/* Returns the socket used for reading. */
+
+int
+packet_get_connection_in()
+{
+       return connection_in;
+}
+
+/* Returns the descriptor used for writing. */
+
+int
+packet_get_connection_out()
+{
+       return connection_out;
+}
+
+/* Closes the connection and clears and frees internal data structures. */
+
+void
+packet_close()
+{
+       if (!initialized)
+               return;
+       initialized = 0;
+       if (connection_in == connection_out) {
+               shutdown(connection_out, SHUT_RDWR);
+               close(connection_out);
+       } else {
+               close(connection_in);
+               close(connection_out);
+       }
+       buffer_free(&input);
+       buffer_free(&output);
+       buffer_free(&outgoing_packet);
+       buffer_free(&incoming_packet);
+       if (compression_buffer_ready) {
+               buffer_free(&compression_buffer);
+               buffer_compress_uninit();
+       }
+}
+
+/* Sets remote side protocol flags. */
+
+void
+packet_set_protocol_flags(u_int protocol_flags)
+{
+       remote_protocol_flags = protocol_flags;
+}
+
+/* Returns the remote protocol flags set earlier by the above function. */
+
+u_int
+packet_get_protocol_flags()
+{
+       return remote_protocol_flags;
+}
+
+/*
+ * Starts packet compression from the next packet on in both directions.
+ * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
+ */
+
+static void
+packet_init_compression(void)
+{
+       if (compression_buffer_ready == 1)
+               return;
+       compression_buffer_ready = 1;
+       buffer_init(&compression_buffer);
+}
+
+void
+packet_start_compression(int level)
+{
+       if (packet_compression && !compat20)
+               fatal("Compression already enabled.");
+       packet_compression = 1;
+       packet_init_compression();
+       buffer_compress_init_send(level);
+       buffer_compress_init_recv();
+}
+
+/*
+ * Causes any further packets to be encrypted using the given key.  The same
+ * key is used for both sending and reception.  However, both directions are
+ * encrypted independently of each other.
+ */
+void
+packet_set_encryption_key(const u_char *key, u_int keylen,
+    int number)
+{
+       Cipher *cipher = cipher_by_number(number);
+       if (cipher == NULL)
+               fatal("packet_set_encryption_key: unknown cipher number %d", number);
+       if (keylen < 20)
+               fatal("packet_set_encryption_key: keylen too small: %d", keylen);
+       cipher_init(&receive_context, cipher, key, keylen, NULL, 0);
+       cipher_init(&send_context, cipher, key, keylen, NULL, 0);
+}
+
+/* Start constructing a packet to send. */
+void
+packet_start(u_char type)
+{
+       u_char buf[9];
+       int len;
+
+       DBG(debug("packet_start[%d]", type));
+       len = compat20 ? 6 : 9;
+       memset(buf, 0, len - 1);
+       buf[len - 1] = type;
+       buffer_clear(&outgoing_packet);
+       buffer_append(&outgoing_packet, buf, len);
+}
+
+/* Append payload. */
+void
+packet_put_char(int value)
+{
+       char ch = value;
+       buffer_append(&outgoing_packet, &ch, 1);
+}
+void
+packet_put_int(u_int value)
+{
+       buffer_put_int(&outgoing_packet, value);
+}
+void
+packet_put_string(const char *buf, u_int len)
+{
+       buffer_put_string(&outgoing_packet, buf, len);
+}
+void
+packet_put_cstring(const char *str)
+{
+       buffer_put_cstring(&outgoing_packet, str);
+}
+void
+packet_put_raw(const char *buf, u_int len)
+{
+       buffer_append(&outgoing_packet, buf, len);
+}
+void
+packet_put_bignum(BIGNUM * value)
+{
+       buffer_put_bignum(&outgoing_packet, value);
+}
+void
+packet_put_bignum2(BIGNUM * value)
+{
+       buffer_put_bignum2(&outgoing_packet, value);
+}
+
+/*
+ * Finalizes and sends the packet.  If the encryption key has been set,
+ * encrypts the packet before sending.
+ */
+
+static void
+packet_send1(void)
+{
+       char buf[8], *cp;
+       int i, padding, len;
+       u_int checksum;
+       u_int32_t rand = 0;
+
+       /*
+        * If using packet compression, compress the payload of the outgoing
+        * packet.
+        */
+       if (packet_compression) {
+               buffer_clear(&compression_buffer);
+               /* Skip padding. */
+               buffer_consume(&outgoing_packet, 8);
+               /* padding */
+               buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
+               buffer_compress(&outgoing_packet, &compression_buffer);
+               buffer_clear(&outgoing_packet);
+               buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
+                             buffer_len(&compression_buffer));
+       }
+       /* Compute packet length without padding (add checksum, remove padding). */
+       len = buffer_len(&outgoing_packet) + 4 - 8;
+
+       /* Insert padding. Initialized to zero in packet_start1() */
+       padding = 8 - len % 8;
+       if (send_context.cipher->number != SSH_CIPHER_NONE) {
+               cp = buffer_ptr(&outgoing_packet);
+               for (i = 0; i < padding; i++) {
+                       if (i % 4 == 0)
+                               rand = arc4random();
+                       cp[7 - i] = rand & 0xff;
+                       rand >>= 8;
+               }
+       }
+       buffer_consume(&outgoing_packet, 8 - padding);
+
+       /* Add check bytes. */
+       checksum = ssh_crc32((u_char *) buffer_ptr(&outgoing_packet),
+           buffer_len(&outgoing_packet));
+       PUT_32BIT(buf, checksum);
+       buffer_append(&outgoing_packet, buf, 4);
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "packet_send plain: ");
+       buffer_dump(&outgoing_packet);
+#endif
+
+       /* Append to output. */
+       PUT_32BIT(buf, len);
+       buffer_append(&output, buf, 4);
+       buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
+       cipher_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
+                      buffer_len(&outgoing_packet));
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "encrypted: ");
+       buffer_dump(&output);
+#endif
+
+       buffer_clear(&outgoing_packet);
+
+       /*
+        * Note that the packet is now only buffered in output.  It won\'t be
+        * actually sent until packet_write_wait or packet_write_poll is
+        * called.
+        */
+}
+
+static void
+set_newkeys(int mode)
+{
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+       CipherContext *cc;
+
+       debug("newkeys: mode %d", mode);
+
+       cc = (mode == MODE_OUT) ? &send_context : &receive_context;
+       if (newkeys[mode] != NULL) {
+               debug("newkeys: rekeying");
+               /* todo: free old keys, reset compression/cipher-ctxt; */
+               memset(cc, 0, sizeof(*cc));
+               enc  = &newkeys[mode]->enc;
+               mac  = &newkeys[mode]->mac;
+               comp = &newkeys[mode]->comp;
+               memset(mac->key, 0, mac->key_len);
+               xfree(enc->name);
+               xfree(enc->iv);
+               xfree(enc->key);
+               xfree(mac->name);
+               xfree(mac->key);
+               xfree(comp->name);
+               xfree(newkeys[mode]);
+       }
+       newkeys[mode] = kex_get_newkeys(mode);
+       if (newkeys[mode] == NULL)
+               fatal("newkeys: no keys for mode %d", mode);
+       enc  = &newkeys[mode]->enc;
+       mac  = &newkeys[mode]->mac;
+       comp = &newkeys[mode]->comp;
+       if (mac->md != NULL)
+               mac->enabled = 1;
+       DBG(debug("cipher_init_context: %d", mode));
+       cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len,
+           enc->iv, enc->cipher->block_size);
+       memset(enc->iv,  0, enc->cipher->block_size);
+       memset(enc->key, 0, enc->cipher->key_len);
+       if (comp->type != 0 && comp->enabled == 0) {
+               packet_init_compression();
+               if (mode == MODE_OUT)
+                       buffer_compress_init_send(6);
+               else
+                       buffer_compress_init_recv();
+               comp->enabled = 1;
+       }
+}
+
+/*
+ * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
+ */
+static void
+packet_send2(void)
+{
+       static u_int32_t seqnr = 0;
+       u_char type, *ucp, *macbuf = NULL;
+       u_char padlen, pad;
+       char *cp;
+       u_int packet_length = 0;
+       u_int i, len;
+       u_int32_t rand = 0;
+       Enc *enc   = NULL;
+       Mac *mac   = NULL;
+       Comp *comp = NULL;
+       int block_size;
+
+       if (newkeys[MODE_OUT] != NULL) {
+               enc  = &newkeys[MODE_OUT]->enc;
+               mac  = &newkeys[MODE_OUT]->mac;
+               comp = &newkeys[MODE_OUT]->comp;
+       }
+       block_size = enc ? enc->cipher->block_size : 8;
+
+       ucp = (u_char *) buffer_ptr(&outgoing_packet);
+       type = ucp[5];
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "plain:     ");
+       buffer_dump(&outgoing_packet);
+#endif
+
+       if (comp && comp->enabled) {
+               len = buffer_len(&outgoing_packet);
+               /* skip header, compress only payload */
+               buffer_consume(&outgoing_packet, 5);
+               buffer_clear(&compression_buffer);
+               buffer_compress(&outgoing_packet, &compression_buffer);
+               buffer_clear(&outgoing_packet);
+               buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
+               buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
+                   buffer_len(&compression_buffer));
+               DBG(debug("compression: raw %d compressed %d", len,
+                   buffer_len(&outgoing_packet)));
+       }
+
+       /* sizeof (packet_len + pad_len + payload) */
+       len = buffer_len(&outgoing_packet);
+
+       /*
+        * calc size of padding, alloc space, get random data,
+        * minimum padding is 4 bytes
+        */
+       padlen = block_size - (len % block_size);
+       if (padlen < 4)
+               padlen += block_size;
+       if (extra_pad) {
+               /* will wrap if extra_pad+padlen > 255 */
+               extra_pad  = roundup(extra_pad, block_size);
+               pad = extra_pad - ((len + padlen) % extra_pad);
+               debug("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
+                   pad, len, padlen, extra_pad);
+               padlen += pad;
+               extra_pad = 0;
+       }
+       buffer_append_space(&outgoing_packet, &cp, padlen);
+       if (enc && enc->cipher->number != SSH_CIPHER_NONE) {
+               /* random padding */
+               for (i = 0; i < padlen; i++) {
+                       if (i % 4 == 0)
+                               rand = arc4random();
+                       cp[i] = rand & 0xff;
+                       rand >>= 8;
+               }
+       } else {
+               /* clear padding */
+               memset(cp, 0, padlen);
+       }
+       /* packet_length includes payload, padding and padding length field */
+       packet_length = buffer_len(&outgoing_packet) - 4;
+       ucp = (u_char *)buffer_ptr(&outgoing_packet);
+       PUT_32BIT(ucp, packet_length);
+       ucp[4] = padlen;
+       DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
+
+       /* compute MAC over seqnr and packet(length fields, payload, padding) */
+       if (mac && mac->enabled) {
+               macbuf = mac_compute(mac, seqnr,
+                   (u_char *) buffer_ptr(&outgoing_packet),
+                   buffer_len(&outgoing_packet));
+               DBG(debug("done calc MAC out #%d", seqnr));
+       }
+       /* encrypt packet and append to output buffer. */
+       buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
+       cipher_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
+           buffer_len(&outgoing_packet));
+       /* append unencrypted MAC */
+       if (mac && mac->enabled)
+               buffer_append(&output, (char *)macbuf, mac->mac_len);
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "encrypted: ");
+       buffer_dump(&output);
+#endif
+       /* increment sequence number for outgoing packets */
+       if (++seqnr == 0)
+               log("outgoing seqnr wraps around");
+       buffer_clear(&outgoing_packet);
+
+       if (type == SSH2_MSG_NEWKEYS)
+               set_newkeys(MODE_OUT);
+}
+
+void
+packet_send()
+{
+       if (compat20)
+               packet_send2();
+       else
+               packet_send1();
+       DBG(debug("packet_send done"));
+}
+
+/*
+ * Waits until a packet has been received, and returns its type.  Note that
+ * no other data is processed until this returns, so this function should not
+ * be used during the interactive session.
+ */
+
+int
+packet_read(int *payload_len_ptr)
+{
+       int type, len;
+       fd_set *setp;
+       char buf[8192];
+       DBG(debug("packet_read()"));
+
+       setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
+           sizeof(fd_mask));
+
+       /* Since we are blocking, ensure that all written packets have been sent. */
+       packet_write_wait();
+
+       /* Stay in the loop until we have received a complete packet. */
+       for (;;) {
+               /* Try to read a packet from the buffer. */
+               type = packet_read_poll(payload_len_ptr);
+               if (!compat20 && (
+                   type == SSH_SMSG_SUCCESS
+                   || type == SSH_SMSG_FAILURE
+                   || type == SSH_CMSG_EOF
+                   || type == SSH_CMSG_EXIT_CONFIRMATION))
+                       packet_integrity_check(*payload_len_ptr, 0, type);
+               /* If we got a packet, return it. */
+               if (type != SSH_MSG_NONE) {
+                       xfree(setp);
+                       return type;
+               }
+               /*
+                * Otherwise, wait for some data to arrive, add it to the
+                * buffer, and try again.
+                */
+               memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
+                   sizeof(fd_mask));
+               FD_SET(connection_in, setp);
+
+               /* Wait for some data to arrive. */
+               while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
+                   (errno == EAGAIN || errno == EINTR))
+                       ;
+
+               /* Read data from the socket. */
+               len = read(connection_in, buf, sizeof(buf));
+               if (len == 0) {
+                       log("Connection closed by %.200s", get_remote_ipaddr());
+                       fatal_cleanup();
+               }
+               if (len < 0)
+                       fatal("Read from socket failed: %.100s", strerror(errno));
+               /* Append it to the buffer. */
+               packet_process_incoming(buf, len);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ * Waits until a packet has been received, verifies that its type matches
+ * that given, and gives a fatal error and exits if there is a mismatch.
+ */
+
+void
+packet_read_expect(int *payload_len_ptr, int expected_type)
+{
+       int type;
+
+       type = packet_read(payload_len_ptr);
+       if (type != expected_type)
+               packet_disconnect("Protocol error: expected packet type %d, got %d",
+                   expected_type, type);
+}
+
+/* Checks if a full packet is available in the data received so far via
+ * packet_process_incoming.  If so, reads the packet; otherwise returns
+ * SSH_MSG_NONE.  This does not wait for data from the connection.
+ *
+ * SSH_MSG_DISCONNECT is handled specially here.  Also,
+ * SSH_MSG_IGNORE messages are skipped by this function and are never returned
+ * to higher levels.
+ *
+ * The returned payload_len does include space consumed by:
+ *     Packet length
+ *     Padding
+ *     Packet type
+ *     Check bytes
+ */
+
+static int
+packet_read_poll1(int *payload_len_ptr)
+{
+       u_int len, padded_len;
+       u_char *ucp, type;
+       char *cp;
+       u_int checksum, stored_checksum;
+
+       /* Check if input size is less than minimum packet size. */
+       if (buffer_len(&input) < 4 + 8)
+               return SSH_MSG_NONE;
+       /* Get length of incoming packet. */
+       ucp = (u_char *) buffer_ptr(&input);
+       len = GET_32BIT(ucp);
+       if (len < 1 + 2 + 2 || len > 256 * 1024)
+               packet_disconnect("Bad packet length %d.", len);
+       padded_len = (len + 8) & ~7;
+
+       /* Check if the packet has been entirely received. */
+       if (buffer_len(&input) < 4 + padded_len)
+               return SSH_MSG_NONE;
+
+       /* The entire packet is in buffer. */
+
+       /* Consume packet length. */
+       buffer_consume(&input, 4);
+
+       /*
+        * Cryptographic attack detector for ssh
+        * (C)1998 CORE-SDI, Buenos Aires Argentina
+        * Ariel Futoransky(futo@core-sdi.com)
+        */
+       if (receive_context.cipher->number != SSH_CIPHER_NONE &&
+           detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED)
+               packet_disconnect("crc32 compensation attack: network attack detected");
+
+       /* Decrypt data to incoming_packet. */
+       buffer_clear(&incoming_packet);
+       buffer_append_space(&incoming_packet, &cp, padded_len);
+       cipher_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
+
+       buffer_consume(&input, padded_len);
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "read_poll plain: ");
+       buffer_dump(&incoming_packet);
+#endif
+
+       /* Compute packet checksum. */
+       checksum = ssh_crc32((u_char *) buffer_ptr(&incoming_packet),
+           buffer_len(&incoming_packet) - 4);
+
+       /* Skip padding. */
+       buffer_consume(&incoming_packet, 8 - len % 8);
+
+       /* Test check bytes. */
+       if (len != buffer_len(&incoming_packet))
+               packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
+                   len, buffer_len(&incoming_packet));
+
+       ucp = (u_char *) buffer_ptr(&incoming_packet) + len - 4;
+       stored_checksum = GET_32BIT(ucp);
+       if (checksum != stored_checksum)
+               packet_disconnect("Corrupted check bytes on input.");
+       buffer_consume_end(&incoming_packet, 4);
+
+       if (packet_compression) {
+               buffer_clear(&compression_buffer);
+               buffer_uncompress(&incoming_packet, &compression_buffer);
+               buffer_clear(&incoming_packet);
+               buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
+                   buffer_len(&compression_buffer));
+       }
+       type = buffer_get_char(&incoming_packet);
+       *payload_len_ptr = buffer_len(&incoming_packet);
+       return type;
+}
+
+static int
+packet_read_poll2(int *payload_len_ptr)
+{
+       static u_int32_t seqnr = 0;
+       static u_int packet_length = 0;
+       u_int padlen, need;
+       u_char *macbuf, *ucp, type;
+       char *cp;
+       int maclen, block_size;
+       Enc *enc   = NULL;
+       Mac *mac   = NULL;
+       Comp *comp = NULL;
+
+       if (newkeys[MODE_IN] != NULL) {
+               enc  = &newkeys[MODE_IN]->enc;
+               mac  = &newkeys[MODE_IN]->mac;
+               comp = &newkeys[MODE_IN]->comp;
+       }
+       maclen = mac && mac->enabled ? mac->mac_len : 0;
+       block_size = enc ? enc->cipher->block_size : 8;
+
+       if (packet_length == 0) {
+               /*
+                * check if input size is less than the cipher block size,
+                * decrypt first block and extract length of incoming packet
+                */
+               if (buffer_len(&input) < block_size)
+                       return SSH_MSG_NONE;
+               buffer_clear(&incoming_packet);
+               buffer_append_space(&incoming_packet, &cp, block_size);
+               cipher_decrypt(&receive_context, cp, buffer_ptr(&input),
+                   block_size);
+               ucp = (u_char *) buffer_ptr(&incoming_packet);
+               packet_length = GET_32BIT(ucp);
+               if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
+                       buffer_dump(&incoming_packet);
+                       packet_disconnect("Bad packet length %d.", packet_length);
+               }
+               DBG(debug("input: packet len %d", packet_length+4));
+               buffer_consume(&input, block_size);
+       }
+       /* we have a partial packet of block_size bytes */
+       need = 4 + packet_length - block_size;
+       DBG(debug("partial packet %d, need %d, maclen %d", block_size,
+           need, maclen));
+       if (need % block_size != 0)
+               fatal("padding error: need %d block %d mod %d",
+                   need, block_size, need % block_size);
+       /*
+        * check if the entire packet has been received and
+        * decrypt into incoming_packet
+        */
+       if (buffer_len(&input) < need + maclen)
+               return SSH_MSG_NONE;
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "read_poll enc/full: ");
+       buffer_dump(&input);
+#endif
+       buffer_append_space(&incoming_packet, &cp, need);
+       cipher_decrypt(&receive_context, cp, buffer_ptr(&input), need);
+       buffer_consume(&input, need);
+       /*
+        * compute MAC over seqnr and packet,
+        * increment sequence number for incoming packet
+        */
+       if (mac && mac->enabled) {
+               macbuf = mac_compute(mac, seqnr,
+                   (u_char *) buffer_ptr(&incoming_packet),
+                   buffer_len(&incoming_packet));
+               if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
+                       packet_disconnect("Corrupted MAC on input.");
+               DBG(debug("MAC #%d ok", seqnr));
+               buffer_consume(&input, mac->mac_len);
+       }
+       if (++seqnr == 0)
+               log("incoming seqnr wraps around");
+
+       /* get padlen */
+       cp = buffer_ptr(&incoming_packet) + 4;
+       padlen = (u_char) *cp;
+       DBG(debug("input: padlen %d", padlen));
+       if (padlen < 4)
+               packet_disconnect("Corrupted padlen %d on input.", padlen);
+
+       /* skip packet size + padlen, discard padding */
+       buffer_consume(&incoming_packet, 4 + 1);
+       buffer_consume_end(&incoming_packet, padlen);
+
+       DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
+       if (comp && comp->enabled) {
+               buffer_clear(&compression_buffer);
+               buffer_uncompress(&incoming_packet, &compression_buffer);
+               buffer_clear(&incoming_packet);
+               buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
+                   buffer_len(&compression_buffer));
+               DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet)));
+       }
+       /*
+        * get packet type, implies consume.
+        * return length of payload (without type field)
+        */
+       type = buffer_get_char(&incoming_packet);
+       if (type == SSH2_MSG_NEWKEYS)
+               set_newkeys(MODE_IN);
+       *payload_len_ptr = buffer_len(&incoming_packet);
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "read/plain[%d]:\r\n", type);
+       buffer_dump(&incoming_packet);
+#endif
+       /* reset for next packet */
+       packet_length = 0;
+       return type;
+}
+
+int
+packet_read_poll(int *payload_len_ptr)
+{
+       int reason;
+       u_char type;
+       char *msg;
+
+       for (;;) {
+               if (compat20) {
+                       type = packet_read_poll2(payload_len_ptr);
+                       if (type)
+                               DBG(debug("received packet type %d", type));
+                       switch(type) {
+                       case SSH2_MSG_IGNORE:
+                               break;
+                       case SSH2_MSG_DEBUG:
+                               packet_get_char();
+                               msg = packet_get_string(NULL);
+                               debug("Remote: %.900s", msg);
+                               xfree(msg);
+                               msg = packet_get_string(NULL);
+                               xfree(msg);
+                               break;
+                       case SSH2_MSG_DISCONNECT:
+                               reason = packet_get_int();
+                               msg = packet_get_string(NULL);
+                               log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(),
+                                       reason, msg);
+                               xfree(msg);
+                               fatal_cleanup();
+                               break;
+                       default:
+                               return type;
+                               break;
+                       }
+               } else {
+                       type = packet_read_poll1(payload_len_ptr);
+                       switch(type) {
+                       case SSH_MSG_IGNORE:
+                               break;
+                       case SSH_MSG_DEBUG:
+                               msg = packet_get_string(NULL);
+                               debug("Remote: %.900s", msg);
+                               xfree(msg);
+                               break;
+                       case SSH_MSG_DISCONNECT:
+                               msg = packet_get_string(NULL);
+                               log("Received disconnect from %s: %.400s", get_remote_ipaddr(),
+                                       msg);
+                               fatal_cleanup();
+                               xfree(msg);
+                               break;
+                       default:
+                               if (type)
+                                       DBG(debug("received packet type %d", type));
+                               return type;
+                               break;
+                       }
+               }
+       }
+}
+
+/*
+ * Buffers the given amount of input characters.  This is intended to be used
+ * together with packet_read_poll.
+ */
+
+void
+packet_process_incoming(const char *buf, u_int len)
+{
+       buffer_append(&input, buf, len);
+}
+
+/* Returns a character from the packet. */
+
+u_int
+packet_get_char()
+{
+       char ch;
+       buffer_get(&incoming_packet, &ch, 1);
+       return (u_char) ch;
+}
+
+/* Returns an integer from the packet data. */
+
+u_int
+packet_get_int()
+{
+       return buffer_get_int(&incoming_packet);
+}
+
+/*
+ * Returns an arbitrary precision integer from the packet data.  The integer
+ * must have been initialized before this call.
+ */
+
+void
+packet_get_bignum(BIGNUM * value, int *length_ptr)
+{
+       *length_ptr = buffer_get_bignum(&incoming_packet, value);
+}
+
+void
+packet_get_bignum2(BIGNUM * value, int *length_ptr)
+{
+       *length_ptr = buffer_get_bignum2(&incoming_packet, value);
+}
+
+char *
+packet_get_raw(int *length_ptr)
+{
+       int bytes = buffer_len(&incoming_packet);
+       if (length_ptr != NULL)
+               *length_ptr = bytes;
+       return buffer_ptr(&incoming_packet);
+}
+
+int
+packet_remaining(void)
+{
+       return buffer_len(&incoming_packet);
+}
+
+/*
+ * Returns a string from the packet data.  The string is allocated using
+ * xmalloc; it is the responsibility of the calling program to free it when
+ * no longer needed.  The length_ptr argument may be NULL, or point to an
+ * integer into which the length of the string is stored.
+ */
+
+char *
+packet_get_string(u_int *length_ptr)
+{
+       return buffer_get_string(&incoming_packet, length_ptr);
+}
+
+/*
+ * Sends a diagnostic message from the server to the client.  This message
+ * can be sent at any time (but not while constructing another message). The
+ * message is printed immediately, but only if the client is being executed
+ * in verbose mode.  These messages are primarily intended to ease debugging
+ * authentication problems.   The length of the formatted message must not
+ * exceed 1024 bytes.  This will automatically call packet_write_wait.
+ */
+
+void
+packet_send_debug(const char *fmt,...)
+{
+       char buf[1024];
+       va_list args;
+
+       if (compat20 && (datafellows & SSH_BUG_DEBUG))
+               return;
+
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       if (compat20) {
+               packet_start(SSH2_MSG_DEBUG);
+               packet_put_char(0);     /* bool: always display */
+               packet_put_cstring(buf);
+               packet_put_cstring("");
+       } else {
+               packet_start(SSH_MSG_DEBUG);
+               packet_put_cstring(buf);
+       }
+       packet_send();
+       packet_write_wait();
+}
+
+/*
+ * Logs the error plus constructs and sends a disconnect packet, closes the
+ * connection, and exits.  This function never returns. The error message
+ * should not contain a newline.  The length of the formatted message must
+ * not exceed 1024 bytes.
+ */
+
+void
+packet_disconnect(const char *fmt,...)
+{
+       char buf[1024];
+       va_list args;
+       static int disconnecting = 0;
+       if (disconnecting)      /* Guard against recursive invocations. */
+               fatal("packet_disconnect called recursively.");
+       disconnecting = 1;
+
+       /*
+        * Format the message.  Note that the caller must make sure the
+        * message is of limited size.
+        */
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       /* Send the disconnect message to the other side, and wait for it to get sent. */
+       if (compat20) {
+               packet_start(SSH2_MSG_DISCONNECT);
+               packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
+               packet_put_cstring(buf);
+               packet_put_cstring("");
+       } else {
+               packet_start(SSH_MSG_DISCONNECT);
+               packet_put_cstring(buf);
+       }
+       packet_send();
+       packet_write_wait();
+
+       /* Stop listening for connections. */
+       channel_close_all();
+
+       /* Close the connection. */
+       packet_close();
+
+       /* Display the error locally and exit. */
+       log("Disconnecting: %.100s", buf);
+       fatal_cleanup();
+}
+
+/* Checks if there is any buffered output, and tries to write some of the output. */
+
+void
+packet_write_poll()
+{
+       int len = buffer_len(&output);
+       if (len > 0) {
+               len = write(connection_out, buffer_ptr(&output), len);
+               if (len <= 0) {
+                       if (errno == EAGAIN)
+                               return;
+                       else
+                               fatal("Write failed: %.100s", strerror(errno));
+               }
+               buffer_consume(&output, len);
+       }
+}
+
+/*
+ * Calls packet_write_poll repeatedly until all pending output data has been
+ * written.
+ */
+
+void
+packet_write_wait()
+{
+       fd_set *setp;
+
+       setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
+           sizeof(fd_mask));
+       packet_write_poll();
+       while (packet_have_data_to_write()) {
+               memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
+                   sizeof(fd_mask));
+               FD_SET(connection_out, setp);
+               while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
+                   (errno == EAGAIN || errno == EINTR))
+                       ;
+               packet_write_poll();
+       }
+       xfree(setp);
+}
+
+/* Returns true if there is buffered data to write to the connection. */
+
+int
+packet_have_data_to_write()
+{
+       return buffer_len(&output) != 0;
+}
+
+/* Returns true if there is not too much data to write to the connection. */
+
+int
+packet_not_very_much_data_to_write()
+{
+       if (interactive_mode)
+               return buffer_len(&output) < 16384;
+       else
+               return buffer_len(&output) < 128 * 1024;
+}
+
+/* Informs that the current session is interactive.  Sets IP flags for that. */
+
+void
+packet_set_interactive(int interactive)
+{
+       static int called = 0;
+#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
+       int lowdelay = IPTOS_LOWDELAY;
+       int throughput = IPTOS_THROUGHPUT;
+#endif
+       int on = 1;
+
+       if (called)
+               return;
+       called = 1;
+
+       /* Record that we are in interactive mode. */
+       interactive_mode = interactive;
+
+       /* Only set socket options if using a socket.  */
+       if (!packet_connection_is_on_socket())
+               return;
+       /*
+        * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
+        */
+       if (interactive) {
+               /*
+                * Set IP options for an interactive connection.  Use
+                * IPTOS_LOWDELAY and TCP_NODELAY.
+                */
+#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
+               if (packet_connection_is_ipv4()) {
+                       if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
+                           (void *) &lowdelay, sizeof(lowdelay)) < 0)
+                               error("setsockopt IPTOS_LOWDELAY: %.100s",
+                                   strerror(errno));
+               }
+#endif
+               if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on,
+                   sizeof(on)) < 0)
+                       error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
+       } else if (packet_connection_is_ipv4()) {
+               /*
+                * Set IP options for a non-interactive connection.  Use
+                * IPTOS_THROUGHPUT.
+                */
+#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
+               if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
+                   sizeof(throughput)) < 0)
+                       error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
+#endif
+       }
+}
+
+/* Returns true if the current connection is interactive. */
+
+int
+packet_is_interactive()
+{
+       return interactive_mode;
+}
+
+int
+packet_set_maxsize(int s)
+{
+       static int called = 0;
+       if (called) {
+               log("packet_set_maxsize: called twice: old %d new %d",
+                   max_packet_size, s);
+               return -1;
+       }
+       if (s < 4 * 1024 || s > 1024 * 1024) {
+               log("packet_set_maxsize: bad size %d", s);
+               return -1;
+       }
+       called = 1;
+       debug("packet_set_maxsize: setting to %d", s);
+       max_packet_size = s;
+       return s;
+}
+
+/* roundup current message to pad bytes */
+void
+packet_add_padding(u_char pad)
+{
+       extra_pad = pad;
+}
+
+/*
+ * 9.2.  Ignored Data Message
+ *
+ *   byte      SSH_MSG_IGNORE
+ *   string    data
+ *
+ * All implementations MUST understand (and ignore) this message at any
+ * time (after receiving the protocol version). No implementation is
+ * required to send them. This message can be used as an additional
+ * protection measure against advanced traffic analysis techniques.
+ */
+void
+packet_send_ignore(int nbytes)
+{
+       u_int32_t rand = 0;
+       int i;
+
+       packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
+       packet_put_int(nbytes);
+       for(i = 0; i < nbytes; i++) {
+               if (i % 4 == 0)
+                       rand = arc4random();
+               packet_put_char(rand & 0xff);
+               rand >>= 8;
+       }
+}
diff --git a/openssh/packet.h b/openssh/packet.h
new file mode 100644 (file)
index 0000000..d547300
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Interface for the packet protocol functions.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: packet.h,v 1.26 2001/11/07 16:03:17 markus Exp $"); */
+
+#ifndef PACKET_H
+#define PACKET_H
+
+#include <openssl/bn.h>
+
+void     packet_set_connection(int, int);
+void     packet_set_nonblocking(void);
+int      packet_get_connection_in(void);
+int      packet_get_connection_out(void);
+void     packet_close(void);
+void    packet_set_encryption_key(const u_char *, u_int, int);
+void     packet_set_protocol_flags(u_int);
+u_int   packet_get_protocol_flags(void);
+void     packet_start_compression(int);
+void     packet_set_interactive(int);
+int      packet_is_interactive(void);
+
+void     packet_start(u_char);
+void     packet_put_char(int ch);
+void     packet_put_int(u_int value);
+void     packet_put_bignum(BIGNUM * value);
+void     packet_put_bignum2(BIGNUM * value);
+void     packet_put_string(const char *buf, u_int len);
+void     packet_put_cstring(const char *str);
+void     packet_put_raw(const char *buf, u_int len);
+void     packet_send(void);
+
+int      packet_read(int *payload_len_ptr);
+void     packet_read_expect(int *payload_len_ptr, int type);
+int      packet_read_poll(int *packet_len_ptr);
+void     packet_process_incoming(const char *buf, u_int len);
+
+u_int   packet_get_char(void);
+u_int   packet_get_int(void);
+void     packet_get_bignum(BIGNUM * value, int *length_ptr);
+void     packet_get_bignum2(BIGNUM * value, int *length_ptr);
+char   *packet_get_raw(int *length_ptr);
+char    *packet_get_string(u_int *length_ptr);
+void     packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void     packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+
+void     packet_write_poll(void);
+void     packet_write_wait(void);
+int      packet_have_data_to_write(void);
+int      packet_not_very_much_data_to_write(void);
+
+int     packet_connection_is_on_socket(void);
+int     packet_connection_is_ipv4(void);
+int     packet_remaining(void);
+void    packet_send_ignore(int);
+void    packet_add_padding(u_char);
+
+void    tty_make_modes(int, struct termios *);
+void    tty_parse_modes(int, int *);
+
+extern int max_packet_size;
+int      packet_set_maxsize(int);
+#define  packet_get_maxsize() max_packet_size
+
+#define packet_integrity_check(payload_len, expected_len, type) \
+do { \
+       int _p = (payload_len), _e = (expected_len); \
+       if (_p != _e) { \
+               log("Packet integrity error (%d != %d) at %s:%d", \
+                   _p, _e, __FILE__, __LINE__); \
+               packet_disconnect("Packet integrity error. (%d)", (type)); \
+       } \
+} while (0)
+
+#define packet_done() \
+do { \
+       int _len = packet_remaining(); \
+       if (_len > 0) { \
+               log("Packet integrity error (%d bytes remaining) at %s:%d", \
+                   _len ,__FILE__, __LINE__); \
+               packet_disconnect("Packet integrity error."); \
+       } \
+} while (0)
+
+#endif                         /* PACKET_H */
diff --git a/openssh/pathnames.h b/openssh/pathnames.h
new file mode 100644 (file)
index 0000000..0470a21
--- /dev/null
@@ -0,0 +1,161 @@
+/*     $OpenBSD: pathnames.h,v 1.9 2001/06/23 02:34:30 markus Exp $    */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef ETCDIR
+#define ETCDIR                         "/etc"
+#endif
+
+#ifndef _PATH_SSH_PIDDIR
+#define _PATH_SSH_PIDDIR               "/var/run"
+#endif
+
+/*
+ * System-wide file containing host keys of known hosts.  This file should be
+ * world-readable.
+ */
+#define _PATH_SSH_SYSTEM_HOSTFILE      ETCDIR "/ssh_known_hosts"
+/* backward compat for protocol 2 */
+#define _PATH_SSH_SYSTEM_HOSTFILE2     ETCDIR "/ssh_known_hosts2"
+
+/*
+ * Of these, ssh_host_key must be readable only by root, whereas ssh_config
+ * should be world-readable.
+ */
+#define _PATH_SERVER_CONFIG_FILE       ETCDIR "/sshd_config"
+#define _PATH_HOST_CONFIG_FILE         ETCDIR "/ssh_config"
+#define _PATH_HOST_KEY_FILE            ETCDIR "/ssh_host_key"
+#define _PATH_HOST_DSA_KEY_FILE                ETCDIR "/ssh_host_dsa_key"
+#define _PATH_HOST_RSA_KEY_FILE                ETCDIR "/ssh_host_rsa_key"
+#define _PATH_DH_MODULI                        ETCDIR "/moduli"
+/* Backwards compatibility */
+#define _PATH_DH_PRIMES                        ETCDIR "/primes"
+
+#ifndef _PATH_SSH_PROGRAM
+#define _PATH_SSH_PROGRAM              "/usr/bin/ssh"
+#endif
+
+/*
+ * The process id of the daemon listening for connections is saved here to
+ * make it easier to kill the correct daemon when necessary.
+ */
+#define _PATH_SSH_DAEMON_PID_FILE      _PATH_SSH_PIDDIR "/sshd.pid"
+
+/*
+ * The directory in user\'s home directory in which the files reside. The
+ * directory should be world-readable (though not all files are).
+ */
+#define _PATH_SSH_USER_DIR             ".ssh"
+
+/*
+ * Per-user file containing host keys of known hosts.  This file need not be
+ * readable by anyone except the user him/herself, though this does not
+ * contain anything particularly secret.
+ */
+#define _PATH_SSH_USER_HOSTFILE                "~/.ssh/known_hosts"
+/* backward compat for protocol 2 */
+#define _PATH_SSH_USER_HOSTFILE2       "~/.ssh/known_hosts2"
+
+/*
+ * Name of the default file containing client-side authentication key. This
+ * file should only be readable by the user him/herself.
+ */
+#define _PATH_SSH_CLIENT_IDENTITY      ".ssh/identity"
+#define _PATH_SSH_CLIENT_ID_DSA                ".ssh/id_dsa"
+#define _PATH_SSH_CLIENT_ID_RSA                ".ssh/id_rsa"
+
+/*
+ * Configuration file in user\'s home directory.  This file need not be
+ * readable by anyone but the user him/herself, but does not contain anything
+ * particularly secret.  If the user\'s home directory resides on an NFS
+ * volume where root is mapped to nobody, this may need to be world-readable.
+ */
+#define _PATH_SSH_USER_CONFFILE                ".ssh/config"
+
+/*
+ * File containing a list of those rsa keys that permit logging in as this
+ * user.  This file need not be readable by anyone but the user him/herself,
+ * but does not contain anything particularly secret.  If the user\'s home
+ * directory resides on an NFS volume where root is mapped to nobody, this
+ * may need to be world-readable.  (This file is read by the daemon which is
+ * running as root.)
+ */
+#define _PATH_SSH_USER_PERMITTED_KEYS  ".ssh/authorized_keys"
+
+/* backward compat for protocol v2 */
+#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
+
+/*
+ * Per-user and system-wide ssh "rc" files.  These files are executed with
+ * /bin/sh before starting the shell or command if they exist.  They will be
+ * passed "proto cookie" as arguments if X11 forwarding with spoofing is in
+ * use.  xauth will be run if neither of these exists.
+ */
+#define _PATH_SSH_USER_RC              ".ssh/rc"
+#define _PATH_SSH_SYSTEM_RC            ETCDIR "/sshrc"
+
+/*
+ * Ssh-only version of /etc/hosts.equiv.  Additionally, the daemon may use
+ * ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
+ */
+#define _PATH_SSH_HOSTS_EQUIV          ETCDIR "/shosts.equiv"
+#define _PATH_RHOSTS_EQUIV             "/etc/hosts.equiv"
+
+/*
+ * Default location of askpass
+ */
+#ifndef _PATH_SSH_ASKPASS_DEFAULT
+#define _PATH_SSH_ASKPASS_DEFAULT      "/usr/X11R6/bin/ssh-askpass"
+#endif
+
+/* xauth for X11 forwarding */
+#ifndef _PATH_XAUTH
+#define _PATH_XAUTH                    "/usr/X11R6/bin/xauth"
+#endif
+
+/* for scp */
+#ifndef _PATH_CP
+#define _PATH_CP                       "cp"
+#endif
+
+/* for sftp */
+#ifndef _PATH_SFTP_SERVER
+#define _PATH_SFTP_SERVER              "/usr/libexec/sftp-server"
+#endif
+#ifndef _PATH_LS
+#define _PATH_LS                       "ls"
+#endif
+
+/* path to login program */
+#ifndef LOGIN_PROGRAM
+# ifdef LOGIN_PROGRAM_FALLBACK
+#  define LOGIN_PROGRAM         LOGIN_PROGRAM_FALLBACK
+# else
+#  define LOGIN_PROGRAM         "/usr/bin/login"
+# endif
+#endif /* LOGIN_PROGRAM */
+
+/* Askpass program define */
+#ifndef ASKPASS_PROGRAM
+#define ASKPASS_PROGRAM         "/usr/lib/ssh/ssh-askpass"
+#endif /* ASKPASS_PROGRAM */
+
+/*
+ * Relevant only when using builtin PRNG.
+ */
+#ifndef SSH_PRNG_SEED_FILE
+# define SSH_PRNG_SEED_FILE      _PATH_SSH_USER_DIR"/prng_seed"
+#endif /* SSH_PRNG_SEED_FILE */
+#ifndef SSH_PRNG_COMMAND_FILE
+# define SSH_PRNG_COMMAND_FILE   ETCDIR "/ssh_prng_cmds"
+#endif /* SSH_PRNG_COMMAND_FILE */
diff --git a/openssh/radix.c b/openssh/radix.c
new file mode 100644 (file)
index 0000000..26b1ebe
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1999 Dug Song.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#include "uuencode.h"
+
+RCSID("$OpenBSD: radix.c,v 1.16 2001/06/23 15:12:19 itojun Exp $");
+
+#ifdef AFS
+#include <krb.h>
+
+#include <radix.h>
+
+typedef u_char my_u_char;
+typedef u_int my_u_int32_t;
+typedef u_short my_u_short;
+
+/* Nasty macros from BIND-4.9.2 */
+
+#define GETSHORT(s, cp) { \
+       register my_u_char *t_cp = (my_u_char *)(cp); \
+       (s) = (((my_u_short)t_cp[0]) << 8) \
+           | (((my_u_short)t_cp[1])) \
+           ; \
+       (cp) += 2; \
+}
+
+#define GETLONG(l, cp) { \
+       register my_u_char *t_cp = (my_u_char *)(cp); \
+       (l) = (((my_u_int32_t)t_cp[0]) << 24) \
+           | (((my_u_int32_t)t_cp[1]) << 16) \
+           | (((my_u_int32_t)t_cp[2]) << 8) \
+           | (((my_u_int32_t)t_cp[3])) \
+           ; \
+       (cp) += 4; \
+}
+
+#define PUTSHORT(s, cp) { \
+       register my_u_short t_s = (my_u_short)(s); \
+       register my_u_char *t_cp = (my_u_char *)(cp); \
+       *t_cp++ = t_s >> 8; \
+       *t_cp   = t_s; \
+       (cp) += 2; \
+}
+
+#define PUTLONG(l, cp) { \
+       register my_u_int32_t t_l = (my_u_int32_t)(l); \
+       register my_u_char *t_cp = (my_u_char *)(cp); \
+       *t_cp++ = t_l >> 24; \
+       *t_cp++ = t_l >> 16; \
+       *t_cp++ = t_l >> 8; \
+       *t_cp   = t_l; \
+       (cp) += 4; \
+}
+
+#define GETSTRING(s, p, p_l) {                 \
+    register char *p_targ = (p) + p_l;         \
+    register char *s_c = (s);                  \
+    register char *p_c = (p);                  \
+    while (*p_c && (p_c < p_targ)) {           \
+       *s_c++ = *p_c++;                        \
+    }                                          \
+    if (p_c == p_targ) {                       \
+       return 1;                               \
+    }                                          \
+    *s_c = *p_c++;                             \
+    (p_l) = (p_l) - (p_c - (p));               \
+    (p) = p_c;                                 \
+}
+
+
+int
+creds_to_radix(CREDENTIALS *creds, u_char *buf, size_t buflen)
+{
+       char *p, *s;
+       int len;
+       char temp[2048];
+
+       p = temp;
+       *p++ = 1;               /* version */
+       s = creds->service;
+       while (*s)
+               *p++ = *s++;
+       *p++ = *s;
+       s = creds->instance;
+       while (*s)
+               *p++ = *s++;
+       *p++ = *s;
+       s = creds->realm;
+       while (*s)
+               *p++ = *s++;
+       *p++ = *s;
+
+       s = creds->pname;
+       while (*s)
+               *p++ = *s++;
+       *p++ = *s;
+       s = creds->pinst;
+       while (*s)
+               *p++ = *s++;
+       *p++ = *s;
+       /* Null string to repeat the realm. */
+       *p++ = '\0';
+
+       PUTLONG(creds->issue_date, p);
+       {
+               u_int endTime;
+               endTime = (u_int) krb_life_to_time(creds->issue_date,
+                                                         creds->lifetime);
+               PUTLONG(endTime, p);
+       }
+
+       memcpy(p, &creds->session, sizeof(creds->session));
+       p += sizeof(creds->session);
+
+       PUTSHORT(creds->kvno, p);
+       PUTLONG(creds->ticket_st.length, p);
+
+       memcpy(p, creds->ticket_st.dat, creds->ticket_st.length);
+       p += creds->ticket_st.length;
+       len = p - temp;
+
+       return (uuencode((u_char *)temp, len, (char *)buf, buflen));
+}
+
+int
+radix_to_creds(const char *buf, CREDENTIALS *creds)
+{
+
+       char *p;
+       int len, tl;
+       char version;
+       char temp[2048];
+
+       len = uudecode(buf, (u_char *)temp, sizeof(temp));
+       if (len < 0)
+               return 0;
+
+       p = temp;
+
+       /* check version and length! */
+       if (len < 1)
+               return 0;
+       version = *p;
+       p++;
+       len--;
+
+       GETSTRING(creds->service, p, len);
+       GETSTRING(creds->instance, p, len);
+       GETSTRING(creds->realm, p, len);
+
+       GETSTRING(creds->pname, p, len);
+       GETSTRING(creds->pinst, p, len);
+       /* Ignore possibly different realm. */
+       while (*p && len)
+               p++, len--;
+       if (len == 0)
+               return 0;
+       p++, len--;
+
+       /* Enough space for remaining fixed-length parts? */
+       if (len < (4 + 4 + sizeof(creds->session) + 2 + 4))
+               return 0;
+
+       GETLONG(creds->issue_date, p);
+       len -= 4;
+       {
+               u_int endTime;
+               GETLONG(endTime, p);
+               len -= 4;
+               creds->lifetime = krb_time_to_life(creds->issue_date, endTime);
+       }
+
+       memcpy(&creds->session, p, sizeof(creds->session));
+       p += sizeof(creds->session);
+       len -= sizeof(creds->session);
+
+       GETSHORT(creds->kvno, p);
+       len -= 2;
+       GETLONG(creds->ticket_st.length, p);
+       len -= 4;
+
+       tl = creds->ticket_st.length;
+       if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat))
+               return 0;
+
+       memcpy(creds->ticket_st.dat, p, tl);
+       p += tl;
+       len -= tl;
+
+       return 1;
+}
+#endif /* AFS */
diff --git a/openssh/radix.h b/openssh/radix.h
new file mode 100644 (file)
index 0000000..e94e4ac
--- /dev/null
@@ -0,0 +1,28 @@
+/*     $OpenBSD: radix.h,v 1.4 2001/06/26 17:27:24 markus Exp $        */
+
+/*
+ * Copyright (c) 1999 Dug Song.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int     creds_to_radix(CREDENTIALS *, u_char *, size_t);
+int     radix_to_creds(const char *, CREDENTIALS *);
diff --git a/openssh/readconf.c b/openssh/readconf.c
new file mode 100644 (file)
index 0000000..63035b3
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for reading the configuration files.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: readconf.c,v 1.91 2001/10/01 21:51:16 markus Exp $");
+
+#include "ssh.h"
+#include "xmalloc.h"
+#include "compat.h"
+#include "cipher.h"
+#include "pathnames.h"
+#include "log.h"
+#include "readconf.h"
+#include "match.h"
+#include "misc.h"
+#include "kex.h"
+#include "mac.h"
+
+/* Format of the configuration file:
+
+   # Configuration data is parsed as follows:
+   #  1. command line options
+   #  2. user-specific file
+   #  3. system-wide file
+   # Any configuration value is only changed the first time it is set.
+   # Thus, host-specific definitions should be at the beginning of the
+   # configuration file, and defaults at the end.
+
+   # Host-specific declarations.  These may override anything above.  A single
+   # host may match multiple declarations; these are processed in the order
+   # that they are given in.
+
+   Host *.ngs.fi ngs.fi
+     FallBackToRsh no
+
+   Host fake.com
+     HostName another.host.name.real.org
+     User blaah
+     Port 34289
+     ForwardX11 no
+     ForwardAgent no
+
+   Host books.com
+     RemoteForward 9999 shadows.cs.hut.fi:9999
+     Cipher 3des
+
+   Host fascist.blob.com
+     Port 23123
+     User tylonen
+     RhostsAuthentication no
+     PasswordAuthentication no
+
+   Host puukko.hut.fi
+     User t35124p
+     ProxyCommand ssh-proxy %h %p
+
+   Host *.fr
+     UseRsh yes
+
+   Host *.su
+     Cipher none
+     PasswordAuthentication no
+
+   # Defaults for various options
+   Host *
+     ForwardAgent no
+     ForwardX11 no
+     RhostsAuthentication yes
+     PasswordAuthentication yes
+     RSAAuthentication yes
+     RhostsRSAAuthentication yes
+     FallBackToRsh no
+     UseRsh no
+     StrictHostKeyChecking yes
+     KeepAlives no
+     IdentityFile ~/.ssh/identity
+     Port 22
+     EscapeChar ~
+
+*/
+
+/* Keyword tokens. */
+
+typedef enum {
+       oBadOption,
+       oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
+       oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
+       oChallengeResponseAuthentication, oXAuthLocation,
+#if defined(KRB4) || defined(KRB5)
+       oKerberosAuthentication,
+#endif
+#if defined(AFS) || defined(KRB5)
+       oKerberosTgtPassing,
+#endif
+#ifdef AFS
+       oAFSTokenPassing,
+#endif
+       oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
+       oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
+       oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
+       oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
+       oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
+       oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
+       oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
+       oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
+       oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
+       oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
+       oClearAllForwardings, oNoHostAuthenticationForLocalhost 
+} OpCodes;
+
+/* Textual representations of the tokens. */
+
+static struct {
+       const char *name;
+       OpCodes opcode;
+} keywords[] = {
+       { "forwardagent", oForwardAgent },
+       { "forwardx11", oForwardX11 },
+       { "xauthlocation", oXAuthLocation },
+       { "gatewayports", oGatewayPorts },
+       { "useprivilegedport", oUsePrivilegedPort },
+       { "rhostsauthentication", oRhostsAuthentication },
+       { "passwordauthentication", oPasswordAuthentication },
+       { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
+       { "kbdinteractivedevices", oKbdInteractiveDevices },
+       { "rsaauthentication", oRSAAuthentication },
+       { "pubkeyauthentication", oPubkeyAuthentication },
+       { "dsaauthentication", oPubkeyAuthentication },             /* alias */
+       { "rhostsrsaauthentication", oRhostsRSAAuthentication },
+       { "hostbasedauthentication", oHostbasedAuthentication },
+       { "challengeresponseauthentication", oChallengeResponseAuthentication },
+       { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
+       { "tisauthentication", oChallengeResponseAuthentication },  /* alias */
+#if defined(KRB4) || defined(KRB5)
+       { "kerberosauthentication", oKerberosAuthentication },
+#endif
+#if defined(AFS) || defined(KRB5)
+       { "kerberostgtpassing", oKerberosTgtPassing },
+#endif
+#ifdef AFS
+       { "afstokenpassing", oAFSTokenPassing },
+#endif
+       { "fallbacktorsh", oFallBackToRsh },
+       { "usersh", oUseRsh },
+       { "identityfile", oIdentityFile },
+       { "identityfile2", oIdentityFile },                     /* alias */
+       { "hostname", oHostName },
+       { "hostkeyalias", oHostKeyAlias },
+       { "proxycommand", oProxyCommand },
+       { "port", oPort },
+       { "cipher", oCipher },
+       { "ciphers", oCiphers },
+       { "macs", oMacs },
+       { "protocol", oProtocol },
+       { "remoteforward", oRemoteForward },
+       { "localforward", oLocalForward },
+       { "user", oUser },
+       { "host", oHost },
+       { "escapechar", oEscapeChar },
+       { "globalknownhostsfile", oGlobalKnownHostsFile },
+       { "userknownhostsfile", oUserKnownHostsFile },          /* obsolete */
+       { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
+       { "userknownhostsfile2", oUserKnownHostsFile2 },        /* obsolete */
+       { "connectionattempts", oConnectionAttempts },
+       { "batchmode", oBatchMode },
+       { "checkhostip", oCheckHostIP },
+       { "stricthostkeychecking", oStrictHostKeyChecking },
+       { "compression", oCompression },
+       { "compressionlevel", oCompressionLevel },
+       { "keepalive", oKeepAlives },
+       { "numberofpasswordprompts", oNumberOfPasswordPrompts },
+       { "loglevel", oLogLevel },
+       { "dynamicforward", oDynamicForward },
+       { "preferredauthentications", oPreferredAuthentications },
+       { "hostkeyalgorithms", oHostKeyAlgorithms },
+       { "bindaddress", oBindAddress },
+       { "smartcarddevice", oSmartcardDevice },
+       { "clearallforwardings", oClearAllForwardings }, 
+       { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 
+       { NULL, 0 }
+};
+
+/*
+ * Adds a local TCP/IP port forward to options.  Never returns if there is an
+ * error.
+ */
+
+void
+add_local_forward(Options *options, u_short port, const char *host,
+                 u_short host_port)
+{
+       Forward *fwd;
+#ifndef HAVE_CYGWIN
+       extern uid_t original_real_uid;
+       if (port < IPPORT_RESERVED && original_real_uid != 0)
+               fatal("Privileged ports can only be forwarded by root.");
+#endif
+       if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
+               fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
+       fwd = &options->local_forwards[options->num_local_forwards++];
+       fwd->port = port;
+       fwd->host = xstrdup(host);
+       fwd->host_port = host_port;
+}
+
+/*
+ * Adds a remote TCP/IP port forward to options.  Never returns if there is
+ * an error.
+ */
+
+void
+add_remote_forward(Options *options, u_short port, const char *host,
+                  u_short host_port)
+{
+       Forward *fwd;
+       if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
+               fatal("Too many remote forwards (max %d).",
+                     SSH_MAX_FORWARDS_PER_DIRECTION);
+       fwd = &options->remote_forwards[options->num_remote_forwards++];
+       fwd->port = port;
+       fwd->host = xstrdup(host);
+       fwd->host_port = host_port;
+}
+
+static void
+clear_forwardings(Options *options)
+{
+       int i;
+
+       for (i = 0; i < options->num_local_forwards; i++)
+               xfree(options->local_forwards[i].host);
+       options->num_local_forwards = 0;
+       for (i = 0; i < options->num_remote_forwards; i++)
+               xfree(options->remote_forwards[i].host);
+       options->num_remote_forwards = 0;
+}
+
+/*
+ * Returns the number of the token pointed to by cp or oBadOption.
+ */
+
+static OpCodes
+parse_token(const char *cp, const char *filename, int linenum)
+{
+       u_int i;
+
+       for (i = 0; keywords[i].name; i++)
+               if (strcasecmp(cp, keywords[i].name) == 0)
+                       return keywords[i].opcode;
+
+       error("%s: line %d: Bad configuration option: %s",
+           filename, linenum, cp);
+       return oBadOption;
+}
+
+/*
+ * Processes a single option line as used in the configuration files. This
+ * only sets those values that have not already been set.
+ */
+
+int
+process_config_line(Options *options, const char *host,
+                   char *line, const char *filename, int linenum,
+                   int *activep)
+{
+       char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
+       int opcode, *intptr, value;
+       u_short fwd_port, fwd_host_port;
+       char sfwd_host_port[6];
+
+       s = line;
+       /* Get the keyword. (Each line is supposed to begin with a keyword). */
+       keyword = strdelim(&s);
+       /* Ignore leading whitespace. */
+       if (*keyword == '\0')
+               keyword = strdelim(&s);
+       if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
+               return 0;
+
+       opcode = parse_token(keyword, filename, linenum);
+
+       switch (opcode) {
+       case oBadOption:
+               /* don't panic, but count bad options */
+               return -1;
+               /* NOTREACHED */
+       case oForwardAgent:
+               intptr = &options->forward_agent;
+parse_flag:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
+               value = 0;      /* To avoid compiler warning... */
+               if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
+                       value = 1;
+               else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
+                       value = 0;
+               else
+                       fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case oForwardX11:
+               intptr = &options->forward_x11;
+               goto parse_flag;
+
+       case oGatewayPorts:
+               intptr = &options->gateway_ports;
+               goto parse_flag;
+
+       case oUsePrivilegedPort:
+               intptr = &options->use_privileged_port;
+               goto parse_flag;
+
+       case oRhostsAuthentication:
+               intptr = &options->rhosts_authentication;
+               goto parse_flag;
+
+       case oPasswordAuthentication:
+               intptr = &options->password_authentication;
+               goto parse_flag;
+
+       case oKbdInteractiveAuthentication:
+               intptr = &options->kbd_interactive_authentication;
+               goto parse_flag;
+
+       case oKbdInteractiveDevices:
+               charptr = &options->kbd_interactive_devices;
+               goto parse_string;
+
+       case oPubkeyAuthentication:
+               intptr = &options->pubkey_authentication;
+               goto parse_flag;
+
+       case oRSAAuthentication:
+               intptr = &options->rsa_authentication;
+               goto parse_flag;
+
+       case oRhostsRSAAuthentication:
+               intptr = &options->rhosts_rsa_authentication;
+               goto parse_flag;
+
+       case oHostbasedAuthentication:
+               intptr = &options->hostbased_authentication;
+               goto parse_flag;
+
+       case oChallengeResponseAuthentication:
+               intptr = &options->challenge_response_authentication;
+               goto parse_flag;
+#if defined(KRB4) || defined(KRB5)
+       case oKerberosAuthentication:
+               intptr = &options->kerberos_authentication;
+               goto parse_flag;
+#endif
+#if defined(AFS) || defined(KRB5)
+       case oKerberosTgtPassing:
+               intptr = &options->kerberos_tgt_passing;
+               goto parse_flag;
+#endif
+#ifdef AFS
+       case oAFSTokenPassing:
+               intptr = &options->afs_token_passing;
+               goto parse_flag;
+#endif
+       case oFallBackToRsh:
+               intptr = &options->fallback_to_rsh;
+               goto parse_flag;
+
+       case oUseRsh:
+               intptr = &options->use_rsh;
+               goto parse_flag;
+
+       case oBatchMode:
+               intptr = &options->batch_mode;
+               goto parse_flag;
+
+       case oCheckHostIP:
+               intptr = &options->check_host_ip;
+               goto parse_flag;
+
+       case oStrictHostKeyChecking:
+               intptr = &options->strict_host_key_checking;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing yes/no/ask argument.",
+                             filename, linenum);
+               value = 0;      /* To avoid compiler warning... */
+               if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
+                       value = 1;
+               else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
+                       value = 0;
+               else if (strcmp(arg, "ask") == 0)
+                       value = 2;
+               else
+                       fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case oCompression:
+               intptr = &options->compression;
+               goto parse_flag;
+
+       case oKeepAlives:
+               intptr = &options->keepalives;
+               goto parse_flag;
+
+       case oNoHostAuthenticationForLocalhost:
+               intptr = &options->no_host_authentication_for_localhost;
+               goto parse_flag;
+
+       case oNumberOfPasswordPrompts:
+               intptr = &options->number_of_password_prompts;
+               goto parse_int;
+
+       case oCompressionLevel:
+               intptr = &options->compression_level;
+               goto parse_int;
+
+       case oIdentityFile:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (*activep) {
+                       intptr = &options->num_identity_files;
+                       if (*intptr >= SSH_MAX_IDENTITY_FILES)
+                               fatal("%.200s line %d: Too many identity files specified (max %d).",
+                                     filename, linenum, SSH_MAX_IDENTITY_FILES);
+                       charptr =  &options->identity_files[*intptr];
+                       *charptr = xstrdup(arg);
+                       *intptr = *intptr + 1;
+               }
+               break;
+
+       case oXAuthLocation:
+               charptr=&options->xauth_location;
+               goto parse_string;
+
+       case oUser:
+               charptr = &options->user;
+parse_string:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (*activep && *charptr == NULL)
+                       *charptr = xstrdup(arg);
+               break;
+
+       case oGlobalKnownHostsFile:
+               charptr = &options->system_hostfile;
+               goto parse_string;
+
+       case oUserKnownHostsFile:
+               charptr = &options->user_hostfile;
+               goto parse_string;
+
+       case oGlobalKnownHostsFile2:
+               charptr = &options->system_hostfile2;
+               goto parse_string;
+
+       case oUserKnownHostsFile2:
+               charptr = &options->user_hostfile2;
+               goto parse_string;
+
+       case oHostName:
+               charptr = &options->hostname;
+               goto parse_string;
+
+       case oHostKeyAlias:
+               charptr = &options->host_key_alias;
+               goto parse_string;
+
+       case oPreferredAuthentications:
+               charptr = &options->preferred_authentications;
+               goto parse_string;
+
+       case oBindAddress:
+               charptr = &options->bind_address;
+               goto parse_string;
+
+       case oSmartcardDevice:
+               charptr = &options->smartcard_device;
+               goto parse_string;
+
+       case oProxyCommand:
+               charptr = &options->proxy_command;
+               string = xstrdup("");
+               while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
+                       string = xrealloc(string, strlen(string) + strlen(arg) + 2);
+                       strcat(string, " ");
+                       strcat(string, arg);
+               }
+               if (*activep && *charptr == NULL)
+                       *charptr = string;
+               else
+                       xfree(string);
+               return 0;
+
+       case oPort:
+               intptr = &options->port;
+parse_int:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (arg[0] < '0' || arg[0] > '9')
+                       fatal("%.200s line %d: Bad number.", filename, linenum);
+
+               /* Octal, decimal, or hex format? */
+               value = strtol(arg, &endofnumber, 0);
+               if (arg == endofnumber)
+                       fatal("%.200s line %d: Bad number.", filename, linenum);
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case oConnectionAttempts:
+               intptr = &options->connection_attempts;
+               goto parse_int;
+
+       case oCipher:
+               intptr = &options->cipher;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               value = cipher_number(arg);
+               if (value == -1)
+                       fatal("%.200s line %d: Bad cipher '%s'.",
+                             filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case oCiphers:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (!ciphers_valid(arg))
+                       fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
+                             filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && options->ciphers == NULL)
+                       options->ciphers = xstrdup(arg);
+               break;
+
+       case oMacs:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (!mac_valid(arg))
+                       fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
+                             filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && options->macs == NULL)
+                       options->macs = xstrdup(arg);
+               break;
+
+       case oHostKeyAlgorithms:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (!key_names_valid2(arg))
+                       fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
+                             filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && options->hostkeyalgorithms == NULL)
+                       options->hostkeyalgorithms = xstrdup(arg);
+               break;
+
+       case oProtocol:
+               intptr = &options->protocol;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               value = proto_spec(arg);
+               if (value == SSH_PROTO_UNKNOWN)
+                       fatal("%.200s line %d: Bad protocol spec '%s'.",
+                             filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && *intptr == SSH_PROTO_UNKNOWN)
+                       *intptr = value;
+               break;
+
+       case oLogLevel:
+               intptr = (int *) &options->log_level;
+               arg = strdelim(&s);
+               value = log_level_number(arg);
+               if (value == (LogLevel) - 1)
+                       fatal("%.200s line %d: unsupported log level '%s'",
+                             filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && (LogLevel) * intptr == -1)
+                       *intptr = (LogLevel) value;
+               break;
+
+       case oLocalForward:
+       case oRemoteForward:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing port argument.",
+                           filename, linenum);
+               if ((fwd_port = a2port(arg)) == 0)
+                       fatal("%.200s line %d: Bad listen port.",
+                           filename, linenum);
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing second argument.",
+                           filename, linenum);
+               if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
+                   sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
+                       fatal("%.200s line %d: Bad forwarding specification.",
+                           filename, linenum);
+               if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
+                       fatal("%.200s line %d: Bad forwarding port.",
+                           filename, linenum);
+               if (*activep) {
+                       if (opcode == oLocalForward)
+                               add_local_forward(options, fwd_port, buf,
+                                   fwd_host_port);
+                       else if (opcode == oRemoteForward)
+                               add_remote_forward(options, fwd_port, buf,
+                                   fwd_host_port);
+               }
+               break;
+
+       case oDynamicForward:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing port argument.",
+                           filename, linenum);
+               fwd_port = a2port(arg);
+               if (fwd_port == 0)
+                       fatal("%.200s line %d: Badly formatted port number.",
+                           filename, linenum);
+               if (*activep)
+                       add_local_forward(options, fwd_port, "socks4", 0);
+               break;
+
+       case oClearAllForwardings:
+               intptr = &options->clear_forwardings;
+               goto parse_flag;
+
+       case oHost:
+               *activep = 0;
+               while ((arg = strdelim(&s)) != NULL && *arg != '\0')
+                       if (match_pattern(host, arg)) {
+                               debug("Applying options for %.100s", arg);
+                               *activep = 1;
+                               break;
+                       }
+               /* Avoid garbage check below, as strdelim is done. */
+               return 0;
+
+       case oEscapeChar:
+               intptr = &options->escape_char;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               if (arg[0] == '^' && arg[2] == 0 &&
+                   (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
+                       value = (u_char) arg[1] & 31;
+               else if (strlen(arg) == 1)
+                       value = (u_char) arg[0];
+               else if (strcmp(arg, "none") == 0)
+                       value = SSH_ESCAPECHAR_NONE;
+               else {
+                       fatal("%.200s line %d: Bad escape character.",
+                             filename, linenum);
+                       /* NOTREACHED */
+                       value = 0;      /* Avoid compiler warning. */
+               }
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       default:
+               fatal("process_config_line: Unimplemented opcode %d", opcode);
+       }
+
+       /* Check that there is no garbage at end of line. */
+       if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
+               fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
+                     filename, linenum, arg);
+       }
+       return 0;
+}
+
+
+/*
+ * Reads the config file and modifies the options accordingly.  Options
+ * should already be initialized before this call.  This never returns if
+ * there is an error.  If the file does not exist, this returns 0.
+ */
+
+int
+read_config_file(const char *filename, const char *host, Options *options)
+{
+       FILE *f;
+       char line[1024];
+       int active, linenum;
+       int bad_options = 0;
+
+       /* Open the file. */
+       f = fopen(filename, "r");
+       if (!f)
+               return 0;
+
+       debug("Reading configuration data %.200s", filename);
+
+       /*
+        * Mark that we are now processing the options.  This flag is turned
+        * on/off by Host specifications.
+        */
+       active = 1;
+       linenum = 0;
+       while (fgets(line, sizeof(line), f)) {
+               /* Update line number counter. */
+               linenum++;
+               if (process_config_line(options, host, line, filename, linenum, &active) != 0)
+                       bad_options++;
+       }
+       fclose(f);
+       if (bad_options > 0)
+               fatal("%s: terminating, %d bad configuration options",
+                     filename, bad_options);
+       return 1;
+}
+
+/*
+ * Initializes options to special values that indicate that they have not yet
+ * been set.  Read_config_file will only set options with this value. Options
+ * are processed in the following order: command line, user config file,
+ * system config file.  Last, fill_default_options is called.
+ */
+
+void
+initialize_options(Options * options)
+{
+       memset(options, 'X', sizeof(*options));
+       options->forward_agent = -1;
+       options->forward_x11 = -1;
+       options->xauth_location = NULL;
+       options->gateway_ports = -1;
+       options->use_privileged_port = -1;
+       options->rhosts_authentication = -1;
+       options->rsa_authentication = -1;
+       options->pubkey_authentication = -1;
+       options->challenge_response_authentication = -1;
+#if defined(KRB4) || defined(KRB5)
+       options->kerberos_authentication = -1;
+#endif
+#if defined(AFS) || defined(KRB5)
+       options->kerberos_tgt_passing = -1;
+#endif
+#ifdef AFS
+       options->afs_token_passing = -1;
+#endif
+       options->password_authentication = -1;
+       options->kbd_interactive_authentication = -1;
+       options->kbd_interactive_devices = NULL;
+       options->rhosts_rsa_authentication = -1;
+       options->hostbased_authentication = -1;
+       options->fallback_to_rsh = -1;
+       options->use_rsh = -1;
+       options->batch_mode = -1;
+       options->check_host_ip = -1;
+       options->strict_host_key_checking = -1;
+       options->compression = -1;
+       options->keepalives = -1;
+       options->compression_level = -1;
+       options->port = -1;
+       options->connection_attempts = -1;
+       options->number_of_password_prompts = -1;
+       options->cipher = -1;
+       options->ciphers = NULL;
+       options->macs = NULL;
+       options->hostkeyalgorithms = NULL;
+       options->protocol = SSH_PROTO_UNKNOWN;
+       options->num_identity_files = 0;
+       options->hostname = NULL;
+       options->host_key_alias = NULL;
+       options->proxy_command = NULL;
+       options->user = NULL;
+       options->escape_char = -1;
+       options->system_hostfile = NULL;
+       options->user_hostfile = NULL;
+       options->system_hostfile2 = NULL;
+       options->user_hostfile2 = NULL;
+       options->num_local_forwards = 0;
+       options->num_remote_forwards = 0;
+       options->clear_forwardings = -1;
+       options->log_level = (LogLevel) - 1;
+       options->preferred_authentications = NULL;
+       options->bind_address = NULL;
+       options->smartcard_device = NULL;
+       options->no_host_authentication_for_localhost = - 1;
+}
+
+/*
+ * Called after processing other sources of option data, this fills those
+ * options for which no value has been specified with their default values.
+ */
+
+void
+fill_default_options(Options * options)
+{
+       int len;
+
+       if (options->forward_agent == -1)
+               options->forward_agent = 0;
+       if (options->forward_x11 == -1)
+               options->forward_x11 = 0;
+#ifdef _PATH_XAUTH
+       if (options->xauth_location == NULL)
+               options->xauth_location = _PATH_XAUTH;
+#endif
+       if (options->gateway_ports == -1)
+               options->gateway_ports = 0;
+       if (options->use_privileged_port == -1)
+               options->use_privileged_port = 0;
+       if (options->rhosts_authentication == -1)
+               options->rhosts_authentication = 1;
+       if (options->rsa_authentication == -1)
+               options->rsa_authentication = 1;
+       if (options->pubkey_authentication == -1)
+               options->pubkey_authentication = 1;
+       if (options->challenge_response_authentication == -1)
+               options->challenge_response_authentication = 1;
+#if defined(KRB4) || defined(KRB5)
+       if (options->kerberos_authentication == -1)
+               options->kerberos_authentication = 1;
+#endif
+#if defined(AFS) || defined(KRB5)
+       if (options->kerberos_tgt_passing == -1)
+               options->kerberos_tgt_passing = 1;
+#endif
+#ifdef AFS
+       if (options->afs_token_passing == -1)
+               options->afs_token_passing = 1;
+#endif
+       if (options->password_authentication == -1)
+               options->password_authentication = 1;
+       if (options->kbd_interactive_authentication == -1)
+               options->kbd_interactive_authentication = 1;
+       if (options->rhosts_rsa_authentication == -1)
+               options->rhosts_rsa_authentication = 1;
+       if (options->hostbased_authentication == -1)
+               options->hostbased_authentication = 0;
+       if (options->fallback_to_rsh == -1)
+               options->fallback_to_rsh = 0;
+       if (options->use_rsh == -1)
+               options->use_rsh = 0;
+       if (options->batch_mode == -1)
+               options->batch_mode = 0;
+       if (options->check_host_ip == -1)
+               options->check_host_ip = 1;
+       if (options->strict_host_key_checking == -1)
+               options->strict_host_key_checking = 2;  /* 2 is default */
+       if (options->compression == -1)
+               options->compression = 0;
+       if (options->keepalives == -1)
+               options->keepalives = 1;
+       if (options->compression_level == -1)
+               options->compression_level = 6;
+       if (options->port == -1)
+               options->port = 0;      /* Filled in ssh_connect. */
+       if (options->connection_attempts == -1)
+               options->connection_attempts = 1;
+       if (options->number_of_password_prompts == -1)
+               options->number_of_password_prompts = 3;
+       /* Selected in ssh_login(). */
+       if (options->cipher == -1)
+               options->cipher = SSH_CIPHER_NOT_SET;
+       /* options->ciphers, default set in myproposals.h */
+       /* options->macs, default set in myproposals.h */
+       /* options->hostkeyalgorithms, default set in myproposals.h */
+       if (options->protocol == SSH_PROTO_UNKNOWN)
+               options->protocol = SSH_PROTO_1|SSH_PROTO_2;
+       if (options->num_identity_files == 0) {
+               if (options->protocol & SSH_PROTO_1) {
+                       len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
+                       options->identity_files[options->num_identity_files] =
+                           xmalloc(len);
+                       snprintf(options->identity_files[options->num_identity_files++],
+                           len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
+               }
+               if (options->protocol & SSH_PROTO_2) {
+                       len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
+                       options->identity_files[options->num_identity_files] =
+                           xmalloc(len);
+                       snprintf(options->identity_files[options->num_identity_files++],
+                           len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
+
+                       len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
+                       options->identity_files[options->num_identity_files] =
+                           xmalloc(len);
+                       snprintf(options->identity_files[options->num_identity_files++],
+                           len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
+               }
+       }
+       if (options->escape_char == -1)
+               options->escape_char = '~';
+       if (options->system_hostfile == NULL)
+               options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
+       if (options->user_hostfile == NULL)
+               options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
+       if (options->system_hostfile2 == NULL)
+               options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
+       if (options->user_hostfile2 == NULL)
+               options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
+       if (options->log_level == (LogLevel) - 1)
+               options->log_level = SYSLOG_LEVEL_INFO;
+       if (options->clear_forwardings == 1)
+               clear_forwardings(options);
+       if (options->no_host_authentication_for_localhost == - 1)
+               options->no_host_authentication_for_localhost = 0;
+       /* options->proxy_command should not be set by default */
+       /* options->user will be set in the main program if appropriate */
+       /* options->hostname will be set in the main program if appropriate */
+       /* options->host_key_alias should not be set by default */
+       /* options->preferred_authentications will be set in ssh */
+}
diff --git a/openssh/readconf.h b/openssh/readconf.h
new file mode 100644 (file)
index 0000000..25ffa46
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for reading the configuration file.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: readconf.h,v 1.40 2001/10/01 21:51:16 markus Exp $"); */
+
+#ifndef READCONF_H
+#define READCONF_H
+
+#include "key.h"
+
+/* Data structure for representing a forwarding request. */
+
+typedef struct {
+       u_short   port;         /* Port to forward. */
+       char     *host;         /* Host to connect. */
+       u_short   host_port;    /* Port to connect on host. */
+}       Forward;
+/* Data structure for representing option data. */
+
+typedef struct {
+       int     forward_agent;  /* Forward authentication agent. */
+       int     forward_x11;    /* Forward X11 display. */
+       char   *xauth_location; /* Location for xauth program */
+       int     gateway_ports;  /* Allow remote connects to forwarded ports. */
+       int     use_privileged_port;    /* Don't use privileged port if false. */
+       int     rhosts_authentication;  /* Try rhosts authentication. */
+       int     rhosts_rsa_authentication;      /* Try rhosts with RSA
+                                                * authentication. */
+       int     rsa_authentication;     /* Try RSA authentication. */
+       int     pubkey_authentication;  /* Try ssh2 pubkey authentication. */
+       int     hostbased_authentication;       /* ssh2's rhosts_rsa */
+       int     challenge_response_authentication;
+                                       /* Try S/Key or TIS, authentication. */
+#if defined(KRB4) || defined(KRB5)
+       int     kerberos_authentication;        /* Try Kerberos authentication. */
+#endif
+#if defined(AFS) || defined(KRB5)
+       int     kerberos_tgt_passing;   /* Try Kerberos TGT passing. */
+#endif
+#ifdef AFS
+       int     afs_token_passing;      /* Try AFS token passing. */
+#endif
+       int     password_authentication;        /* Try password
+                                                * authentication. */
+       int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
+       char    *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
+       int     fallback_to_rsh;/* Use rsh if cannot connect with ssh. */
+       int     use_rsh;        /* Always use rsh (don\'t try ssh). */
+       int     batch_mode;     /* Batch mode: do not ask for passwords. */
+       int     check_host_ip;  /* Also keep track of keys for IP address */
+       int     strict_host_key_checking;       /* Strict host key checking. */
+       int     compression;    /* Compress packets in both directions. */
+       int     compression_level;      /* Compression level 1 (fast) to 9
+                                        * (best). */
+       int     keepalives;     /* Set SO_KEEPALIVE. */
+       LogLevel log_level;     /* Level for logging. */
+
+       int     port;           /* Port to connect. */
+       int     connection_attempts;    /* Max attempts (seconds) before
+                                        * giving up */
+       int     number_of_password_prompts;     /* Max number of password
+                                                * prompts. */
+       int     cipher;         /* Cipher to use. */
+       char   *ciphers;        /* SSH2 ciphers in order of preference. */
+       char   *macs;           /* SSH2 macs in order of preference. */
+       char   *hostkeyalgorithms;      /* SSH2 server key types in order of preference. */
+       int     protocol;       /* Protocol in order of preference. */
+       char   *hostname;       /* Real host to connect. */
+       char   *host_key_alias; /* hostname alias for .ssh/known_hosts */
+       char   *proxy_command;  /* Proxy command for connecting the host. */
+       char   *user;           /* User to log in as. */
+       int     escape_char;    /* Escape character; -2 = none */
+
+       char   *system_hostfile;/* Path for /etc/ssh_known_hosts. */
+       char   *user_hostfile;  /* Path for $HOME/.ssh/known_hosts. */
+       char   *system_hostfile2;
+       char   *user_hostfile2;
+       char   *preferred_authentications;
+       char   *bind_address;   /* local socket address for connection to sshd */
+       char   *smartcard_device; /* Smartcard reader device */
+
+       int     num_identity_files;     /* Number of files for RSA/DSA identities. */
+       char   *identity_files[SSH_MAX_IDENTITY_FILES];
+       Key    *identity_keys[SSH_MAX_IDENTITY_FILES];
+
+       /* Local TCP/IP forward requests. */
+       int     num_local_forwards;
+       Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+
+       /* Remote TCP/IP forward requests. */
+       int     num_remote_forwards;
+       Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+       int     clear_forwardings;
+       int     no_host_authentication_for_localhost;
+}       Options;
+
+
+void     initialize_options(Options *);
+void     fill_default_options(Options *);
+int     read_config_file(const char *, const char *, Options *);
+
+int
+process_config_line(Options *, const char *, char *, const char *, int, int *);
+
+void    add_local_forward(Options *, u_short, const char *, u_short);
+void    add_remote_forward(Options *, u_short, const char *, u_short);
+
+#endif                         /* READCONF_H */
diff --git a/openssh/readpass.c b/openssh/readpass.c
new file mode 100644 (file)
index 0000000..a042981
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1988, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: readpass.c,v 1.23 2001/11/08 10:51:08 markus Exp $");
+
+#include "xmalloc.h"
+#include "readpass.h"
+#include "pathnames.h"
+#include "log.h"
+#include "ssh.h"
+
+static char *
+ssh_askpass(char *askpass, const char *msg)
+{
+       pid_t pid;
+       size_t len;
+       char *pass;
+       int p[2], status;
+       char buf[1024];
+
+       if (fflush(stdout) != 0)
+               error("ssh_askpass: fflush: %s", strerror(errno));
+       if (askpass == NULL)
+               fatal("internal error: askpass undefined");
+       if (pipe(p) < 0) {
+               error("ssh_askpass: pipe: %s", strerror(errno));
+               return xstrdup("");
+       }
+       if ((pid = fork()) < 0) {
+               error("ssh_askpass: fork: %s", strerror(errno));
+               return xstrdup("");
+       }
+       if (pid == 0) {
+               seteuid(getuid());
+               setuid(getuid());
+               close(p[0]);
+               if (dup2(p[1], STDOUT_FILENO) < 0)
+                       fatal("ssh_askpass: dup2: %s", strerror(errno));
+               execlp(askpass, askpass, msg, (char *) 0);
+               fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
+       }
+       close(p[1]);
+       len = read(p[0], buf, sizeof buf -1);
+       close(p[0]);
+       while (waitpid(pid, &status, 0) < 0)
+               if (errno != EINTR)
+                       break;
+       if (len <= 1)
+               return xstrdup("");
+       buf[len] = '\0';
+       buf[strcspn(buf, "\r\n")] = '\0';
+       pass = xstrdup(buf);
+       memset(buf, 0, sizeof(buf));
+       return pass;
+}
+
+/*
+ * Reads a passphrase from /dev/tty with echo turned off/on.  Returns the
+ * passphrase (allocated with xmalloc).  Exits if EOF is encountered. If
+ * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no
+ * tty is available
+ */
+char *
+read_passphrase(const char *prompt, int flags)
+{
+       char *askpass = NULL, *ret, buf[1024];
+       int rppflags, use_askpass = 0, ttyfd;
+
+       rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF;
+       if (flags & RP_ALLOW_STDIN) {
+               if (!isatty(STDIN_FILENO))
+                       use_askpass = 1;
+       } else {
+               rppflags |= RPP_REQUIRE_TTY;
+               ttyfd = open("/dev/tty", O_RDWR);
+               if (ttyfd >= 0)
+                       close(ttyfd);
+               else
+                       use_askpass = 1;
+       }
+
+       if (use_askpass && getenv("DISPLAY")) {
+               if (getenv(SSH_ASKPASS_ENV))
+                       askpass = getenv(SSH_ASKPASS_ENV);
+               else
+                       askpass = _PATH_SSH_ASKPASS_DEFAULT;
+               return ssh_askpass(askpass, prompt);
+       }
+
+       if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL)
+               return xstrdup("");
+
+       ret = xstrdup(buf);
+       memset(buf, 'x', sizeof buf);
+       return ret;
+}
diff --git a/openssh/readpass.h b/openssh/readpass.h
new file mode 100644 (file)
index 0000000..229973c
--- /dev/null
@@ -0,0 +1,18 @@
+/*     $OpenBSD: readpass.h,v 1.6 2001/06/26 17:27:24 markus Exp $     */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#define RP_ECHO                        0x0001
+#define RP_ALLOW_STDIN         0x0002
+
+char   *read_passphrase(const char *, int);
diff --git a/openssh/rijndael.c b/openssh/rijndael.c
new file mode 100644 (file)
index 0000000..f28a9c6
--- /dev/null
@@ -0,0 +1,1245 @@
+/*     $OpenBSD: rijndael.c,v 1.12 2001/09/13 09:48:39 markus Exp $ */
+
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "rijndael.h"
+
+#define FULL_UNROLL
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+       0x01000000, 0x02000000, 0x04000000, 0x08000000,
+       0x10000000, 0x20000000, 0x40000000, 0x80000000,
+       0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return     the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+       int i = 0;
+       u32 temp;
+
+       rk[0] = GETU32(cipherKey     );
+       rk[1] = GETU32(cipherKey +  4);
+       rk[2] = GETU32(cipherKey +  8);
+       rk[3] = GETU32(cipherKey + 12);
+       if (keyBits == 128) {
+               for (;;) {
+                       temp  = rk[3];
+                       rk[4] = rk[0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[5] = rk[1] ^ rk[4];
+                       rk[6] = rk[2] ^ rk[5];
+                       rk[7] = rk[3] ^ rk[6];
+                       if (++i == 10) {
+                               return 10;
+                       }
+                       rk += 4;
+               }
+       }
+       rk[4] = GETU32(cipherKey + 16);
+       rk[5] = GETU32(cipherKey + 20);
+       if (keyBits == 192) {
+               for (;;) {
+                       temp = rk[ 5];
+                       rk[ 6] = rk[ 0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[ 7] = rk[ 1] ^ rk[ 6];
+                       rk[ 8] = rk[ 2] ^ rk[ 7];
+                       rk[ 9] = rk[ 3] ^ rk[ 8];
+                       if (++i == 8) {
+                               return 12;
+                       }
+                       rk[10] = rk[ 4] ^ rk[ 9];
+                       rk[11] = rk[ 5] ^ rk[10];
+                       rk += 6;
+               }
+       }
+       rk[6] = GETU32(cipherKey + 24);
+       rk[7] = GETU32(cipherKey + 28);
+       if (keyBits == 256) {
+        for (;;) {
+               temp = rk[ 7];
+               rk[ 8] = rk[ 0] ^
+                       (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                       (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                       (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                       (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                       rcon[i];
+               rk[ 9] = rk[ 1] ^ rk[ 8];
+               rk[10] = rk[ 2] ^ rk[ 9];
+               rk[11] = rk[ 3] ^ rk[10];
+                       if (++i == 7) {
+                               return 14;
+                       }
+               temp = rk[11];
+               rk[12] = rk[ 4] ^
+                       (Te4[(temp >> 24)       ] & 0xff000000) ^
+                       (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+                       (Te4[(temp >>  8) & 0xff] & 0x0000ff00) ^
+                       (Te4[(temp      ) & 0xff] & 0x000000ff);
+               rk[13] = rk[ 5] ^ rk[12];
+               rk[14] = rk[ 6] ^ rk[13];
+               rk[15] = rk[ 7] ^ rk[14];
+
+                       rk += 8;
+        }
+       }
+       return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return     the number of rounds for the given cipher key size.
+ */
+static int
+rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits,
+    int have_encrypt) {
+       int Nr, i, j;
+       u32 temp;
+
+       if (have_encrypt) {
+               Nr = have_encrypt;
+       } else {
+               /* expand the cipher key: */
+               Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+       }
+       /* invert the order of the round keys: */
+       for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+               temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+               temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+               temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+               temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+       }
+       /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+       for (i = 1; i < Nr; i++) {
+               rk += 4;
+               rk[0] =
+                       Td0[Te4[(rk[0] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[0] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[0]      ) & 0xff] & 0xff];
+               rk[1] =
+                       Td0[Te4[(rk[1] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[1] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[1]      ) & 0xff] & 0xff];
+               rk[2] =
+                       Td0[Te4[(rk[2] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[2] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[2]      ) & 0xff] & 0xff];
+               rk[3] =
+                       Td0[Te4[(rk[3] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[3] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[3]      ) & 0xff] & 0xff];
+       }
+       return Nr;
+}
+
+static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+       u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+       s0 = GETU32(pt     ) ^ rk[0];
+       s1 = GETU32(pt +  4) ^ rk[1];
+       s2 = GETU32(pt +  8) ^ rk[2];
+       s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+       /* round 2: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+    /* round 3: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+       /* round 4: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+    /* round 5: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+       /* round 6: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+    /* round 7: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+       /* round 8: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+    /* round 9: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+    if (Nr > 10) {
+        /* round 10: */
+        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+        if (Nr > 12) {
+            /* round 12: */
+            s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+            s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+            s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+            s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+            t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+            t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+            t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+        }
+    }
+    rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+        * Nr - 1 full rounds:
+        */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Te0[(s0 >> 24)       ] ^
+            Te1[(s1 >> 16) & 0xff] ^
+            Te2[(s2 >>  8) & 0xff] ^
+            Te3[(s3      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Te0[(s1 >> 24)       ] ^
+            Te1[(s2 >> 16) & 0xff] ^
+            Te2[(s3 >>  8) & 0xff] ^
+            Te3[(s0      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Te0[(s2 >> 24)       ] ^
+            Te1[(s3 >> 16) & 0xff] ^
+            Te2[(s0 >>  8) & 0xff] ^
+            Te3[(s1      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Te0[(s3 >> 24)       ] ^
+            Te1[(s0 >> 16) & 0xff] ^
+            Te2[(s1 >>  8) & 0xff] ^
+            Te3[(s2      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0[(t0 >> 24)       ] ^
+            Te1[(t1 >> 16) & 0xff] ^
+            Te2[(t2 >>  8) & 0xff] ^
+            Te3[(t3      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Te0[(t1 >> 24)       ] ^
+            Te1[(t2 >> 16) & 0xff] ^
+            Te2[(t3 >>  8) & 0xff] ^
+            Te3[(t0      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Te0[(t2 >> 24)       ] ^
+            Te1[(t3 >> 16) & 0xff] ^
+            Te2[(t0 >>  8) & 0xff] ^
+            Te3[(t1      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Te0[(t3 >> 24)       ] ^
+            Te1[(t0 >> 16) & 0xff] ^
+            Te2[(t1 >>  8) & 0xff] ^
+            Te3[(t2      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+       s0 =
+               (Te4[(t0 >> 24)       ] & 0xff000000) ^
+               (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t3      ) & 0xff] & 0x000000ff) ^
+               rk[0];
+       PUTU32(ct     , s0);
+       s1 =
+               (Te4[(t1 >> 24)       ] & 0xff000000) ^
+               (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t0      ) & 0xff] & 0x000000ff) ^
+               rk[1];
+       PUTU32(ct +  4, s1);
+       s2 =
+               (Te4[(t2 >> 24)       ] & 0xff000000) ^
+               (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t1      ) & 0xff] & 0x000000ff) ^
+               rk[2];
+       PUTU32(ct +  8, s2);
+       s3 =
+               (Te4[(t3 >> 24)       ] & 0xff000000) ^
+               (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t2      ) & 0xff] & 0x000000ff) ^
+               rk[3];
+       PUTU32(ct + 12, s3);
+}
+
+static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
+       u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+    s0 = GETU32(ct     ) ^ rk[0];
+    s1 = GETU32(ct +  4) ^ rk[1];
+    s2 = GETU32(ct +  8) ^ rk[2];
+    s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+    if (Nr > 10) {
+        /* round 10: */
+        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+        if (Nr > 12) {
+            /* round 12: */
+            s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+            s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+            s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+            s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+            t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+            t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+            t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+        }
+    }
+       rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Td0[(s0 >> 24)       ] ^
+            Td1[(s3 >> 16) & 0xff] ^
+            Td2[(s2 >>  8) & 0xff] ^
+            Td3[(s1      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Td0[(s1 >> 24)       ] ^
+            Td1[(s0 >> 16) & 0xff] ^
+            Td2[(s3 >>  8) & 0xff] ^
+            Td3[(s2      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Td0[(s2 >> 24)       ] ^
+            Td1[(s1 >> 16) & 0xff] ^
+            Td2[(s0 >>  8) & 0xff] ^
+            Td3[(s3      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Td0[(s3 >> 24)       ] ^
+            Td1[(s2 >> 16) & 0xff] ^
+            Td2[(s1 >>  8) & 0xff] ^
+            Td3[(s0      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td0[(t0 >> 24)       ] ^
+            Td1[(t3 >> 16) & 0xff] ^
+            Td2[(t2 >>  8) & 0xff] ^
+            Td3[(t1      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Td0[(t1 >> 24)       ] ^
+            Td1[(t0 >> 16) & 0xff] ^
+            Td2[(t3 >>  8) & 0xff] ^
+            Td3[(t2      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Td0[(t2 >> 24)       ] ^
+            Td1[(t1 >> 16) & 0xff] ^
+            Td2[(t0 >>  8) & 0xff] ^
+            Td3[(t3      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Td0[(t3 >> 24)       ] ^
+            Td1[(t2 >> 16) & 0xff] ^
+            Td2[(t1 >>  8) & 0xff] ^
+            Td3[(t0      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+       s0 =
+               (Td4[(t0 >> 24)       ] & 0xff000000) ^
+               (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t1      ) & 0xff] & 0x000000ff) ^
+               rk[0];
+       PUTU32(pt     , s0);
+       s1 =
+               (Td4[(t1 >> 24)       ] & 0xff000000) ^
+               (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t2      ) & 0xff] & 0x000000ff) ^
+               rk[1];
+       PUTU32(pt +  4, s1);
+       s2 =
+               (Td4[(t2 >> 24)       ] & 0xff000000) ^
+               (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t3      ) & 0xff] & 0x000000ff) ^
+               rk[2];
+       PUTU32(pt +  8, s2);
+       s3 =
+               (Td4[(t3 >> 24)       ] & 0xff000000) ^
+               (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t0      ) & 0xff] & 0x000000ff) ^
+               rk[3];
+       PUTU32(pt + 12, s3);
+}
+
+void
+rijndael_set_key(rijndael_ctx *ctx, u_char *key, int bits, int encrypt)
+{
+       ctx->Nr = rijndaelKeySetupEnc(ctx->ek, key, bits);
+        if (encrypt) {
+               ctx->decrypt = 0;
+               memset(ctx->dk, 0, sizeof(ctx->dk));
+       } else {
+               ctx->decrypt = 1;
+               memcpy(ctx->dk, ctx->ek, sizeof(ctx->ek));
+                rijndaelKeySetupDec(ctx->dk, key, bits, ctx->Nr);
+       }
+}
+
+void
+rijndael_decrypt(rijndael_ctx *ctx, u_char *src, u_char *dst)
+{
+       rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst);
+}
+
+void
+rijndael_encrypt(rijndael_ctx *ctx, u_char *src, u_char *dst)
+{
+       rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst);
+}
diff --git a/openssh/rijndael.h b/openssh/rijndael.h
new file mode 100644 (file)
index 0000000..18a4d80
--- /dev/null
@@ -0,0 +1,51 @@
+/*     $OpenBSD: rijndael.h,v 1.11 2001/09/13 09:48:39 markus Exp $ */
+
+/**
+ * rijndael-alg-fst.h
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RIJNDAEL_H
+#define __RIJNDAEL_H
+
+#define MAXKC  (256/32)
+#define MAXKB  (256/8)
+#define MAXNR  14
+
+typedef unsigned char  u8;     
+typedef unsigned short u16;    
+typedef unsigned int   u32;
+
+/*  The structure for key information */
+typedef struct {
+       int     decrypt;
+       int     Nr;                     /* key-length-dependent number of rounds */
+       u32     ek[4*(MAXNR + 1)];      /* encrypt key schedule */
+       u32     dk[4*(MAXNR + 1)];      /* decrypt key schedule */
+} rijndael_ctx;
+
+void    rijndael_set_key(rijndael_ctx *, u_char *, int, int);
+void    rijndael_decrypt(rijndael_ctx *, u_char *, u_char *);
+void    rijndael_encrypt(rijndael_ctx *, u_char *, u_char *);
+
+#endif /* __RIJNDAEL_H */
diff --git a/openssh/rsa.c b/openssh/rsa.c
new file mode 100644 (file)
index 0000000..113ee7f
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * Copyright (c) 1999 Niels Provos.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Description of the RSA algorithm can be found e.g. from the following
+ * sources:
+ *
+ *   Bruce Schneier: Applied Cryptography.  John Wiley & Sons, 1994.
+ *
+ *   Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
+ *   Computer Security.  Prentice-Hall, 1989.
+ *
+ *   Man Young Rhee: Cryptography and Secure Data Communications.  McGraw-Hill,
+ *   1994.
+ *
+ *   R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
+ *   System and Method.  US Patent 4,405,829, 1983.
+ *
+ *   Hans Riesel: Prime Numbers and Computer Methods for Factorization.
+ *   Birkhauser, 1994.
+ *
+ *   The RSA Frequently Asked Questions document by RSA Data Security,
+ *   Inc., 1995.
+ *
+ *   RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as
+ * included below:
+ *
+ *     [gone - had to be deleted - what a pity]
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: rsa.c,v 1.23 2001/06/27 05:42:24 markus Exp $");
+
+#include "rsa.h"
+#include "log.h"
+#include "xmalloc.h"
+
+void
+rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
+{
+       u_char *inbuf, *outbuf;
+       int len, ilen, olen;
+
+       if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
+               fatal("rsa_public_encrypt() exponent too small or not odd");
+
+       olen = BN_num_bytes(key->n);
+       outbuf = xmalloc(olen);
+
+       ilen = BN_num_bytes(in);
+       inbuf = xmalloc(ilen);
+       BN_bn2bin(in, inbuf);
+
+       if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
+           RSA_PKCS1_PADDING)) <= 0)
+               fatal("rsa_public_encrypt() failed");
+
+       BN_bin2bn(outbuf, len, out);
+
+       memset(outbuf, 0, olen);
+       memset(inbuf, 0, ilen);
+       xfree(outbuf);
+       xfree(inbuf);
+}
+
+int
+rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
+{
+       u_char *inbuf, *outbuf;
+       int len, ilen, olen;
+
+       olen = BN_num_bytes(key->n);
+       outbuf = xmalloc(olen);
+
+       ilen = BN_num_bytes(in);
+       inbuf = xmalloc(ilen);
+       BN_bn2bin(in, inbuf);
+
+       if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
+           RSA_PKCS1_PADDING)) <= 0) {
+               error("rsa_private_decrypt() failed");
+       } else {
+               BN_bin2bn(outbuf, len, out);
+       }
+       memset(outbuf, 0, olen);
+       memset(inbuf, 0, ilen);
+       xfree(outbuf);
+       xfree(inbuf);
+       return len;
+}
+
+void
+rsa_generate_additional_parameters(RSA *rsa)
+{
+       BIGNUM *aux;
+       BN_CTX *ctx;
+       /* Generate additional parameters */
+       aux = BN_new();
+       ctx = BN_CTX_new();
+
+       BN_sub(aux, rsa->q, BN_value_one());
+       BN_mod(rsa->dmq1, rsa->d, aux, ctx);
+
+       BN_sub(aux, rsa->p, BN_value_one());
+       BN_mod(rsa->dmp1, rsa->d, aux, ctx);
+
+       BN_clear_free(aux);
+       BN_CTX_free(ctx);
+}
+
diff --git a/openssh/rsa.h b/openssh/rsa.h
new file mode 100644 (file)
index 0000000..2f596d4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * RSA key generation, encryption and decryption.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: rsa.h,v 1.14 2001/06/27 05:42:24 markus Exp $"); */
+
+#ifndef RSA_H
+#define RSA_H
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+void    rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
+int     rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
+void    rsa_generate_additional_parameters(RSA *);
+
+#endif                         /* RSA_H */
diff --git a/openssh/scard.c b/openssh/scard.c
new file mode 100644 (file)
index 0000000..251e5d3
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#ifdef SMARTCARD
+RCSID("$OpenBSD: scard.c,v 1.15 2001/09/28 09:49:31 djm Exp $");
+
+#include <openssl/engine.h>
+#include <sectok.h>
+
+#include "key.h"
+#include "log.h"
+#include "xmalloc.h"
+#include "scard.h"
+
+#define CLA_SSH 0x05
+#define INS_DECRYPT 0x10
+#define INS_GET_KEYLENGTH 0x20
+#define INS_GET_PUBKEY 0x30
+#define INS_GET_RESPONSE 0xc0
+
+#define MAX_BUF_SIZE 256
+
+static int sc_fd = -1;
+static char *sc_reader_id = NULL;
+static int cla = 0x00; /* class */
+
+/* interface to libsectok */
+
+static int 
+sc_open(void)
+{
+       int sw;
+
+       if (sc_fd >= 0)
+               return sc_fd;
+
+       sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
+       if (sc_fd < 0) {
+               error("sectok_open failed: %s", sectok_get_sw(sw));
+               return SCARD_ERROR_FAIL;
+       }
+       if (! sectok_cardpresent(sc_fd)) {
+               debug("smartcard in reader %s not present, skipping",
+                   sc_reader_id);
+               sc_close();
+               return SCARD_ERROR_NOCARD;
+       }
+       if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
+               error("sectok_reset failed: %s", sectok_get_sw(sw));
+               sc_fd = -1;
+               return SCARD_ERROR_FAIL;
+       }
+       if ((cla = cyberflex_inq_class(sc_fd)) < 0)
+               cla = 0;
+
+       debug("sc_open ok %d", sc_fd);
+       return sc_fd;
+}
+
+static int 
+sc_enable_applet(void)
+{
+       static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
+       int sw = 0;
+
+       /* select applet id */
+       sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
+       if (!sectok_swOK(sw)) {
+               error("sectok_apdu failed: %s", sectok_get_sw(sw));
+               sc_close();
+               return -1;
+       }
+       return 0;
+}
+
+static int 
+sc_init(void)
+{
+       int status;
+
+       status = sc_open();
+       if (status == SCARD_ERROR_NOCARD) {
+               return SCARD_ERROR_NOCARD;
+       }
+       if (status < 0 ) {
+               error("sc_open failed");
+               return status;
+       }
+       if (sc_enable_applet() < 0) {
+               error("sc_enable_applet failed");
+               return SCARD_ERROR_APPLET;
+       }
+       return 0;
+}
+
+static int 
+sc_read_pubkey(Key * k)
+{
+       u_char buf[2], *n;
+       char *p;
+       int len, sw, status = -1;
+
+       len = sw = 0;
+       n = NULL;
+
+       if (sc_fd < 0) {
+               status = sc_init();
+               if (status < 0 )
+                       goto err;
+       }
+
+       /* get key size */
+       sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
+            sizeof(buf), buf, &sw);
+       if (!sectok_swOK(sw)) {
+               error("could not obtain key length: %s", sectok_get_sw(sw));
+               goto err;
+       }
+       len = (buf[0] << 8) | buf[1];
+       len /= 8;
+       debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
+
+       n = xmalloc(len);
+       /* get n */
+       sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
+       if (!sectok_swOK(sw)) {
+               error("could not obtain public key: %s", sectok_get_sw(sw));
+               goto err;
+       }
+
+       debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
+
+       if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
+               error("c_read_pubkey: BN_bin2bn failed");
+               goto err;
+       }
+
+       /* currently the java applet just stores 'n' */
+       if (!BN_set_word(k->rsa->e, 35)) {
+               error("c_read_pubkey: BN_set_word(e, 35) failed");
+               goto err;
+       }
+
+       status = 0;
+       p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+       debug("fingerprint %d %s", key_size(k), p);
+       xfree(p);
+
+err:
+       if (n != NULL)
+               xfree(n);
+       sc_close();
+       return status;
+}
+
+/* private key operations */
+
+static int
+sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
+{
+       u_char *padded = NULL;
+       int sw, len, olen, status = -1;
+
+       debug("sc_private_decrypt called");
+
+       olen = len = sw = 0;
+       if (sc_fd < 0) {
+               status = sc_init();
+               if (status < 0 )
+                       goto err;
+       }
+       if (padding != RSA_PKCS1_PADDING)
+               goto err;
+
+       len = BN_num_bytes(rsa->n);
+       padded = xmalloc(len);
+
+       sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
+       if (!sectok_swOK(sw)) {
+               error("sc_private_decrypt: INS_DECRYPT failed: %s",
+                   sectok_get_sw(sw));
+               goto err;
+       }
+       sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
+            len, padded, &sw);
+       if (!sectok_swOK(sw)) {
+               error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
+                   sectok_get_sw(sw));
+               goto err;
+       }
+       olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
+           len);
+err:
+       if (padded)
+               xfree(padded);
+       sc_close();
+       return (olen >= 0 ? olen : status);
+}
+
+static int
+sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
+{
+       u_char *padded = NULL;
+       int sw, len, status = -1;
+
+       len = sw = 0;
+       if (sc_fd < 0) {
+               status = sc_init();
+               if (status < 0 )
+                       goto err;
+       }
+       if (padding != RSA_PKCS1_PADDING)
+               goto err;
+
+       debug("sc_private_encrypt called");
+       len = BN_num_bytes(rsa->n);
+       padded = xmalloc(len);
+
+       if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
+               error("RSA_padding_add_PKCS1_type_1 failed");
+               goto err;
+       }
+       sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
+       if (!sectok_swOK(sw)) {
+               error("sc_private_decrypt: INS_DECRYPT failed: %s",
+                   sectok_get_sw(sw));
+               goto err;
+       }
+       sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
+            len, to, &sw);
+       if (!sectok_swOK(sw)) {
+               error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
+                   sectok_get_sw(sw));
+               goto err;
+       }
+err:
+       if (padded)
+               xfree(padded);
+       sc_close();
+       return (len >= 0 ? len : status);
+}
+
+/* called on free */
+
+static int (*orig_finish)(RSA *rsa) = NULL;
+
+static int
+sc_finish(RSA *rsa)
+{
+       if (orig_finish)
+               orig_finish(rsa);
+       sc_close();
+       return 1;
+}
+
+
+/* engine for overloading private key operations */
+
+static ENGINE *smart_engine = NULL;
+static RSA_METHOD smart_rsa =
+{
+       "sectok",
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       0,
+       NULL,
+};
+
+ENGINE *
+sc_get_engine(void)
+{
+       RSA_METHOD *def;
+
+       def = RSA_get_default_openssl_method();
+
+       /* overload */
+       smart_rsa.rsa_priv_enc  = sc_private_encrypt;
+       smart_rsa.rsa_priv_dec  = sc_private_decrypt;
+
+       /* save original */
+       orig_finish             = def->finish;
+       smart_rsa.finish        = sc_finish;
+
+       /* just use the OpenSSL version */
+       smart_rsa.rsa_pub_enc   = def->rsa_pub_enc;
+       smart_rsa.rsa_pub_dec   = def->rsa_pub_dec;
+       smart_rsa.rsa_mod_exp   = def->rsa_mod_exp;
+       smart_rsa.bn_mod_exp    = def->bn_mod_exp;
+       smart_rsa.init          = def->init;
+       smart_rsa.flags         = def->flags;
+       smart_rsa.app_data      = def->app_data;
+       smart_rsa.rsa_sign      = def->rsa_sign;
+       smart_rsa.rsa_verify    = def->rsa_verify;
+
+       smart_engine = ENGINE_new();
+
+       ENGINE_set_id(smart_engine, "sectok");
+       ENGINE_set_name(smart_engine, "libsectok");
+       ENGINE_set_RSA(smart_engine, &smart_rsa);
+       ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
+       ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
+       ENGINE_set_RAND(smart_engine, RAND_SSLeay());
+       ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
+
+       return smart_engine;
+}
+
+void
+sc_close(void)
+{
+       if (sc_fd >= 0) {
+               sectok_close(sc_fd);
+               sc_fd = -1;
+       }
+}
+
+Key *
+sc_get_key(const char *id)
+{
+       Key *k;
+       int status;
+
+       if (sc_reader_id != NULL)
+               xfree(sc_reader_id);
+       sc_reader_id = xstrdup(id);
+
+       k = key_new(KEY_RSA);
+       if (k == NULL) {
+               return NULL;
+       }
+       status = sc_read_pubkey(k);
+       if (status == SCARD_ERROR_NOCARD) {
+               key_free(k);
+               return NULL;
+       }
+       if (status < 0 ) {
+               error("sc_read_pubkey failed");
+               key_free(k);
+               return NULL;
+       }
+       return k;
+}
+#endif /* SMARTCARD */
diff --git a/openssh/scard.h b/openssh/scard.h
new file mode 100644 (file)
index 0000000..57189df
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $OpenBSD: scard.h,v 1.6 2001/08/01 22:03:33 markus Exp $ */
+
+#include <openssl/engine.h>
+
+#ifndef SCARD_H
+#define SCARD_H
+
+#define SCARD_ERROR_FAIL       -1
+#define SCARD_ERROR_NOCARD     -2
+#define SCARD_ERROR_APPLET     -3
+
+Key    *sc_get_key(const char*);
+ENGINE *sc_get_engine(void);
+void    sc_close(void);
+
+#endif
diff --git a/openssh/scard/Makefile.in b/openssh/scard/Makefile.in
new file mode 100644 (file)
index 0000000..f2d596a
--- /dev/null
@@ -0,0 +1,27 @@
+# $Id$
+
+prefix=@prefix@
+datadir=@datadir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+
+INSTALL=@INSTALL@
+
+VPATH=@srcdir@
+
+all:
+
+Ssh.bin:  Ssh.bin.uu
+       uudecode Ssh.bin.uu
+
+clean:
+       rm -rf Ssh.bin
+
+distprep: Ssh.bin
+
+distclean: clean
+       rm -f Makefile *~
+
+install: $(srcdir)/Ssh.bin
+       $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir)
+       $(INSTALL) -m 0644 $(srcdir)/Ssh.bin $(DESTDIR)$(datadir)/Ssh.bin
diff --git a/openssh/scard/Ssh.bin b/openssh/scard/Ssh.bin
new file mode 100644 (file)
index 0000000..8645398
Binary files /dev/null and b/openssh/scard/Ssh.bin differ
diff --git a/openssh/scard/Ssh.bin.uu b/openssh/scard/Ssh.bin.uu
new file mode 100644 (file)
index 0000000..1062e21
--- /dev/null
@@ -0,0 +1,16 @@
+begin 644 Ssh.bin
+M`P)!%P`501P`;``!`C@"`/Y@\`4`_J'P!0!!%T$;`?Z@\`4`01=!&@'^>/,!
+M`4$701P!_G#S%P'^0],1`?Y@\!0`_G/S'0#^<]4``D$7L`4`_F'3``!!%T$9
+M`?YATP4`_G/5"P7^8=,'`OZAT`$!_J#0$@1!%T$8`0```$$7!`$&`/Y@`;@`
+M`$$8\`H(`$$9\`H``$$:\@\``$$;\B$``$$<\A```/`&__(```0(`!8```9C
+M""T#"<(H+00$*"T%""A;`&19``#P$/_R`P(&`0#(```38`!!70!&$UP`1@09
+M":1+``D*D`!@`"@37`!&!!E6`````*(````$____P````*$````0````*@``
+M`"````"-````,````&H37`!&`QD(2@`)"FX`8``H$UP`1@<9"@#_/2!@`$L1
+M2@`)"F<`8``H$UP`'A-<`$8($1-<`$8(7@!0"!%@`%59"C\`8`!:*PIS:&``
+M6BL37`!&`P,*`(!@`%\K`PH`@&``55D37`!&`P<H$UP`1@0#*`,%8`!565D*
+M;0!@`"A9`/`"__(!`0$)``@```J0`&``*%D`\!/_\@$!`@D`#```8D$7+5\`
+M/"M9````\!+_]@$!`P$`&```$UP`'EX`,D4`#Q-<`!X*`,@)$%X`-P17L`7_
+M\@$!!`(`/```$U\``!-B_J$M7P`%70`*$V+^H"U?``]=`!038OYX+0H$`%\`
+<&5T`'@H$`&``(T4`"0IG`&``*!->`"U9````````
+`
+end
diff --git a/openssh/scard/Ssh.java b/openssh/scard/Ssh.java
new file mode 100644 (file)
index 0000000..a26ae01
--- /dev/null
@@ -0,0 +1,143 @@
+// $Id$
+//
+// Ssh.java
+// SSH / smartcard integration project, smartcard side
+//
+// Tomoko Fukuzawa, created, Feb., 2000
+//
+// Naomaru Itoi, modified, Apr., 2000
+//
+
+// copyright 2000
+// the regents of the university of michigan
+// all rights reserved
+//
+// permission is granted to use, copy, create derivative works
+// and redistribute this software and such derivative works
+// for any purpose, so long as the name of the university of
+// michigan is not used in any advertising or publicity
+// pertaining to the use or distribution of this software
+// without specific, written prior authorization.  if the
+// above copyright notice or any other identification of the
+// university of michigan is included in any copy of any
+// portion of this software, then the disclaimer below must
+// also be included.
+//
+// this software is provided as is, without representation
+// from the university of michigan as to its fitness for any
+// purpose, and without warranty by the university of
+// michigan of any kind, either express or implied, including
+// without limitation the implied warranties of
+// merchantability and fitness for a particular purpose. the
+// regents of the university of michigan shall not be liable
+// for any damages, including special, indirect, incidental, or
+// consequential damages, with respect to any claim arising
+// out of or in connection with the use of the software, even
+// if it has been or is hereafter advised of the possibility of
+// such damages.
+
+import javacard.framework.*;
+import javacardx.framework.*;
+import javacardx.crypto.*;
+
+public class Ssh extends javacard.framework.Applet
+{
+    /* constants declaration */
+    // code of CLA byte in the command APDU header
+    static final byte Ssh_CLA =(byte)0x05;
+
+    // codes of INS byte in the command APDU header
+    static final byte DECRYPT = (byte) 0x10;
+    static final byte GET_KEYLENGTH = (byte) 0x20;
+    static final byte GET_PUBKEY = (byte) 0x30;
+    static final byte GET_RESPONSE = (byte) 0xc0;
+
+    /* instance variables declaration */
+    static final short keysize = 1024;
+
+    //RSA_CRT_PrivateKey rsakey;
+    AsymKey rsakey;
+    CyberflexFile file;
+    CyberflexOS os;
+
+    byte buffer[];
+
+    static byte[] keyHdr = {(byte)0xC2, (byte)0x01, (byte)0x05};
+
+    private Ssh()
+    {
+       file = new CyberflexFile();
+       os = new CyberflexOS();
+
+       rsakey = new RSA_CRT_PrivateKey (keysize);
+
+       if ( ! rsakey.isSupportedLength (keysize) )
+           ISOException.throwIt (ISO.SW_WRONG_LENGTH);
+
+       register();
+    } // end of the constructor
+
+    public boolean select() {
+       if (!rsakey.isInitialized())
+           rsakey.setKeyInstance ((short)0xc8, (short)0x10);
+
+       return true;
+    }
+
+    public static void install(APDU apdu)
+    {
+       new Ssh();      // create a Ssh applet instance (card)
+    } // end of install method
+
+    public static void main(String args[]) {
+       ISOException.throwIt((short) 0x9000);
+    }
+
+    public void process(APDU apdu)
+    {
+       // APDU object carries a byte array (buffer) to
+       // transfer incoming and outgoing APDU header
+       // and data bytes between card and CAD
+       buffer = apdu.getBuffer();
+
+       // verify that if the applet can accept this
+       // APDU message
+       // NI: change suggested by Wayne Dyksen, Purdue
+       if (buffer[ISO.OFFSET_INS] == ISO.INS_SELECT)
+           ISOException.throwIt(ISO.SW_NO_ERROR);
+
+       switch (buffer[ISO.OFFSET_INS]) {
+       case DECRYPT:
+           if (buffer[ISO.OFFSET_CLA] != Ssh_CLA)
+               ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);
+           //decrypt (apdu);
+           short size = (short) (buffer[ISO.OFFSET_LC] & 0x00FF);
+
+           if (apdu.setIncomingAndReceive() != size)
+               ISOException.throwIt (ISO.SW_WRONG_LENGTH);
+
+           rsakey.cryptoUpdate (buffer, (short) ISO.OFFSET_CDATA, size,
+                                buffer, (short) ISO.OFFSET_CDATA);
+
+           apdu.setOutgoingAndSend ((short) ISO.OFFSET_CDATA, size);
+           return;
+       case GET_PUBKEY:
+           file.selectFile((short)(0x3f<<8)); // select root
+           file.selectFile((short)(('s'<<8)|'h')); // select public key file
+           os.readBinaryFile (buffer, (short)0, (short)0, (short)(keysize/8));
+           apdu.setOutgoingAndSend((short)0, (short)(keysize/8));
+           return;
+       case GET_KEYLENGTH:
+           buffer[0] = (byte)((keysize >> 8) & 0xff);
+           buffer[1] = (byte)(keysize & 0xff);
+           apdu.setOutgoingAndSend ((short)0, (short)2);
+           return;
+       case GET_RESPONSE:
+           return;
+       default:
+           ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED);
+       }
+
+    } // end of process method
+
+} // end of class Ssh
diff --git a/openssh/scp.1 b/openssh/scp.1
new file mode 100644 (file)
index 0000000..d51e680
--- /dev/null
@@ -0,0 +1,152 @@
+.\"  -*- nroff -*-
+.\"
+.\" scp.1
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\"
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\"                    All rights reserved
+.\"
+.\" Created: Sun May  7 00:14:37 1995 ylo
+.\"
+.\" $OpenBSD: scp.1,v 1.20 2001/09/17 23:56:07 stevesk Exp $
+.\"
+.Dd September 25, 1999
+.Dt SCP 1
+.Os
+.Sh NAME
+.Nm scp
+.Nd secure copy (remote file copy program)
+.Sh SYNOPSIS
+.Nm scp
+.Op Fl pqrvBC46
+.Op Fl F Ar ssh_config
+.Op Fl S Ar program
+.Op Fl P Ar port
+.Op Fl c Ar cipher
+.Op Fl i Ar identity_file
+.Op Fl o Ar ssh_option
+.Sm off
+.Oo
+.Op Ar user@
+.Ar host1 No :
+.Oc Ns Ar file1
+.Sm on
+.Op Ar ...
+.Sm off
+.Oo
+.Op Ar user@
+.Ar host2 No :
+.Oc Ar file2
+.Sm on
+.Sh DESCRIPTION
+.Nm
+copies files between hosts on a network.
+It uses
+.Xr ssh 1
+for data transfer, and uses the same authentication and provides the
+same security as
+.Xr ssh 1 .
+Unlike
+.Xr rcp 1 ,
+.Nm
+will ask for passwords or passphrases if they are needed for
+authentication.
+.Pp
+Any file name may contain a host and user specification to indicate
+that the file is to be copied to/from that host.
+Copies between two remote hosts are permitted.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c Ar cipher
+Selects the cipher to use for encrypting the data transfer.
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl i Ar identity_file
+Selects the file from which the identity (private key) for RSA
+authentication is read.
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl p
+Preserves modification times, access times, and modes from the
+original file.
+.It Fl r
+Recursively copy entire directories.
+.It Fl v
+Verbose mode.
+Causes
+.Nm
+and
+.Xr ssh 1
+to print debugging messages about their progress.
+This is helpful in
+debugging connection, authentication, and configuration problems.
+.It Fl B
+Selects batch mode (prevents asking for passwords or passphrases).
+.It Fl q
+Disables the progress meter.
+.It Fl C
+Compression enable.
+Passes the
+.Fl C
+flag to
+.Xr ssh 1
+to enable compression.
+.It Fl F Ar ssh_config
+Specifies an alternative
+per-user configuration file for
+.Nm ssh .
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl P Ar port
+Specifies the port to connect to on the remote host.
+Note that this option is written with a capital
+.Sq P ,
+because
+.Fl p
+is already reserved for preserving the times and modes of the file in
+.Xr rcp 1 .
+.It Fl S Ar program
+Name of
+.Ar program
+to use for the encrypted connection.
+The program must understand
+.Xr ssh 1
+options.
+.It Fl o Ar ssh_option
+Can be used to pass options to
+.Nm ssh
+in the format used in the
+.Xr ssh 1
+configuration file. This is useful for specifying options
+for which there is no separate
+.Nm scp
+command-line flag.  For example, forcing the use of protocol
+version 1 is specified using
+.Ic scp -oProtocol=1 .
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.El
+.Sh AUTHORS
+Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi>
+.Sh HISTORY
+.Nm
+is based on the
+.Xr rcp 1
+program in BSD source code from the Regents of the University of
+California.
+.Sh SEE ALSO
+.Xr rcp 1 ,
+.Xr sftp 1 ,
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
diff --git a/openssh/scp.c b/openssh/scp.c
new file mode 100644 (file)
index 0000000..fb4d309
--- /dev/null
@@ -0,0 +1,1218 @@
+/*
+ * scp - secure remote copy.  This is basically patched BSD rcp which
+ * uses ssh to do the data transfer (instead of using rcmd).
+ *
+ * NOTE: This version should NOT be suid root.  (This uses ssh to
+ * do the transfer and ssh has the necessary privileges.)
+ *
+ * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+ * Copyright (c) 1999 Aaron Campbell.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Parts from:
+ *
+ * Copyright (c) 1983, 1990, 1992, 1993, 1995
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: scp.c,v 1.85 2001/10/01 08:06:28 markus Exp $");
+
+#include "xmalloc.h"
+#include "atomicio.h"
+#include "pathnames.h"
+#include "log.h"
+#include "misc.h"
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+/* For progressmeter() -- number of seconds before xfer considered "stalled" */
+#define STALLTIME      5
+/* alarm() interval for updating progress meter */
+#define PROGRESSTIME   1
+
+/* Progress meter bar */
+#define BAR \
+       "************************************************************"\
+       "************************************************************"\
+       "************************************************************"\
+       "************************************************************"
+#define MAX_BARLENGTH (sizeof(BAR) - 1)
+
+/* Visual statistics about files as they are transferred. */
+void progressmeter(int);
+
+/* Returns width of the terminal (for progress meter calculations). */
+int getttywidth(void);
+int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);
+
+/* Struct for addargs */
+arglist args;
+
+/* Time a transfer started. */
+static struct timeval start;
+
+/* Number of bytes of current file transferred so far. */
+volatile off_t statbytes;
+
+/* Total size of current file. */
+off_t totalbytes = 0;
+
+/* Name of current file being transferred. */
+char *curfile;
+
+/* This is set to non-zero to enable verbose mode. */
+int verbose_mode = 0;
+
+/* This is set to zero if the progressmeter is not desired. */
+int showprogress = 1;
+
+/* This is the program to execute for the secured connection. ("ssh" or -S) */
+char *ssh_program = _PATH_SSH_PROGRAM;
+
+/*
+ * This function executes the given command as the specified user on the
+ * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
+ * assigns the input and output file descriptors on success.
+ */
+
+int
+do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
+{
+       int pin[2], pout[2], reserved[2];
+
+       if (verbose_mode)
+               fprintf(stderr,
+                   "Executing: program %s host %s, user %s, command %s\n",
+                   ssh_program, host,
+                   remuser ? remuser : "(unspecified)", cmd);
+
+       /*
+        * Reserve two descriptors so that the real pipes won't get
+        * descriptors 0 and 1 because that will screw up dup2 below.
+        */
+       pipe(reserved);
+
+       /* Create a socket pair for communicating with ssh. */
+       if (pipe(pin) < 0)
+               fatal("pipe: %s", strerror(errno));
+       if (pipe(pout) < 0)
+               fatal("pipe: %s", strerror(errno));
+
+       /* Free the reserved descriptors. */
+       close(reserved[0]);
+       close(reserved[1]);
+
+       /* For a child to execute the command on the remote host using ssh. */
+       if (fork() == 0)  {
+               /* Child. */
+               close(pin[1]);
+               close(pout[0]);
+               dup2(pin[0], 0);
+               dup2(pout[1], 1);
+               close(pin[0]);
+               close(pout[1]);
+
+               args.list[0] = ssh_program;
+               if (remuser != NULL)
+                       addargs(&args, "-l%s", remuser);
+               addargs(&args, "%s", host);
+               addargs(&args, "%s", cmd);
+
+               execvp(ssh_program, args.list);
+               perror(ssh_program);
+               exit(1);
+       }
+       /* Parent.  Close the other side, and return the local side. */
+       close(pin[0]);
+       *fdout = pin[1];
+       close(pout[1]);
+       *fdin = pout[0];
+       return 0;
+}
+
+typedef struct {
+       int cnt;
+       char *buf;
+} BUF;
+
+BUF *allocbuf(BUF *, int, int);
+void lostconn(int);
+void nospace(void);
+int okname(char *);
+void run_err(const char *,...);
+void verifydir(char *);
+
+struct passwd *pwd;
+uid_t userid;
+int errs, remin, remout;
+int pflag, iamremote, iamrecursive, targetshouldbedirectory;
+
+#define        CMDNEEDS        64
+char cmd[CMDNEEDS];            /* must hold "rcp -r -p -d\0" */
+
+int response(void);
+void rsource(char *, struct stat *);
+void sink(int, char *[]);
+void source(int, char *[]);
+void tolocal(int, char *[]);
+void toremote(char *, int, char *[]);
+void usage(void);
+
+int
+main(argc, argv)
+       int argc;
+       char *argv[];
+{
+       int ch, fflag, tflag;
+       char *targ;
+       extern char *optarg;
+       extern int optind;
+
+       __progname = get_progname(argv[0]);
+
+       args.list = NULL;
+       addargs(&args, "ssh");          /* overwritten with ssh_program */
+       addargs(&args, "-x");
+       addargs(&args, "-oForwardAgent no");
+       addargs(&args, "-oFallBackToRsh no");
+       addargs(&args, "-oClearAllForwardings yes");
+
+       fflag = tflag = 0;
+       while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)
+               switch (ch) {
+               /* User-visible flags. */
+               case '4':
+               case '6':
+               case 'C':
+                       addargs(&args, "-%c", ch);
+                       break;
+               case 'o':
+               case 'c':
+               case 'i':
+               case 'F':
+                       addargs(&args, "-%c%s", ch, optarg);
+                       break;
+               case 'P':
+                       addargs(&args, "-p%s", optarg);
+                       break;
+               case 'B':
+                       addargs(&args, "-oBatchmode yes");
+                       break;
+               case 'p':
+                       pflag = 1;
+                       break;
+               case 'r':
+                       iamrecursive = 1;
+                       break;
+               case 'S':
+                       ssh_program = xstrdup(optarg);
+                       break;
+               case 'v':
+                       addargs(&args, "-v");
+                       verbose_mode = 1;
+                       break;
+               case 'q':
+                       showprogress = 0;
+                       break;
+
+               /* Server options. */
+               case 'd':
+                       targetshouldbedirectory = 1;
+                       break;
+               case 'f':       /* "from" */
+                       iamremote = 1;
+                       fflag = 1;
+                       break;
+               case 't':       /* "to" */
+                       iamremote = 1;
+                       tflag = 1;
+#ifdef HAVE_CYGWIN
+                       setmode(0, O_BINARY);
+#endif
+                       break;
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if ((pwd = getpwuid(userid = getuid())) == NULL)
+               fatal("unknown user %d", (int) userid);
+
+       if (!isatty(STDERR_FILENO))
+               showprogress = 0;
+
+       remin = STDIN_FILENO;
+       remout = STDOUT_FILENO;
+
+       if (fflag) {
+               /* Follow "protocol", send data. */
+               (void) response();
+               source(argc, argv);
+               exit(errs != 0);
+       }
+       if (tflag) {
+               /* Receive data. */
+               sink(argc, argv);
+               exit(errs != 0);
+       }
+       if (argc < 2)
+               usage();
+       if (argc > 2)
+               targetshouldbedirectory = 1;
+
+       remin = remout = -1;
+       /* Command to be executed on remote system using "ssh". */
+       (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
+           verbose_mode ? " -v" : "",
+           iamrecursive ? " -r" : "", pflag ? " -p" : "",
+           targetshouldbedirectory ? " -d" : "");
+
+       (void) signal(SIGPIPE, lostconn);
+
+       if ((targ = colon(argv[argc - 1])))     /* Dest is remote host. */
+               toremote(targ, argc, argv);
+       else {
+               tolocal(argc, argv);    /* Dest is local host. */
+               if (targetshouldbedirectory)
+                       verifydir(argv[argc - 1]);
+       }
+       exit(errs != 0);
+}
+
+void
+toremote(targ, argc, argv)
+       char *targ, *argv[];
+       int argc;
+{
+       int i, len;
+       char *bp, *host, *src, *suser, *thost, *tuser;
+
+       *targ++ = 0;
+       if (*targ == 0)
+               targ = ".";
+
+       if ((thost = strchr(argv[argc - 1], '@'))) {
+               /* user@host */
+               *thost++ = 0;
+               tuser = argv[argc - 1];
+               if (*tuser == '\0')
+                       tuser = NULL;
+               else if (!okname(tuser))
+                       exit(1);
+       } else {
+               thost = argv[argc - 1];
+               tuser = NULL;
+       }
+
+       for (i = 0; i < argc - 1; i++) {
+               src = colon(argv[i]);
+               if (src) {      /* remote to remote */
+                       static char *ssh_options =
+                           "-x -o'FallBackToRsh no' "
+                           "-o'ClearAllForwardings yes'";
+                       *src++ = 0;
+                       if (*src == 0)
+                               src = ".";
+                       host = strchr(argv[i], '@');
+                       len = strlen(ssh_program) + strlen(argv[i]) +
+                           strlen(src) + (tuser ? strlen(tuser) : 0) +
+                           strlen(thost) + strlen(targ) +
+                           strlen(ssh_options) + CMDNEEDS + 20;
+                       bp = xmalloc(len);
+                       if (host) {
+                               *host++ = 0;
+                               host = cleanhostname(host);
+                               suser = argv[i];
+                               if (*suser == '\0')
+                                       suser = pwd->pw_name;
+                               else if (!okname(suser))
+                                       continue;
+                               snprintf(bp, len,
+                                   "%s%s %s -n "
+                                   "-l %s %s %s %s '%s%s%s:%s'",
+                                   ssh_program, verbose_mode ? " -v" : "",
+                                   ssh_options, suser, host, cmd, src,
+                                   tuser ? tuser : "", tuser ? "@" : "",
+                                   thost, targ);
+                       } else {
+                               host = cleanhostname(argv[i]);
+                               snprintf(bp, len,
+                                   "exec %s%s %s -n %s "
+                                   "%s %s '%s%s%s:%s'",
+                                   ssh_program, verbose_mode ? " -v" : "",
+                                   ssh_options, host, cmd, src,
+                                   tuser ? tuser : "", tuser ? "@" : "",
+                                   thost, targ);
+                       }
+                       if (verbose_mode)
+                               fprintf(stderr, "Executing: %s\n", bp);
+                       (void) system(bp);
+                       (void) xfree(bp);
+               } else {        /* local to remote */
+                       if (remin == -1) {
+                               len = strlen(targ) + CMDNEEDS + 20;
+                               bp = xmalloc(len);
+                               (void) snprintf(bp, len, "%s -t %s", cmd, targ);
+                               host = cleanhostname(thost);
+                               if (do_cmd(host, tuser, bp, &remin,
+                                   &remout, argc) < 0)
+                                       exit(1);
+                               if (response() < 0)
+                                       exit(1);
+                               (void) xfree(bp);
+                       }
+                       source(1, argv + i);
+               }
+       }
+}
+
+void
+tolocal(argc, argv)
+       int argc;
+       char *argv[];
+{
+       int i, len;
+       char *bp, *host, *src, *suser;
+
+       for (i = 0; i < argc - 1; i++) {
+               if (!(src = colon(argv[i]))) {  /* Local to local. */
+                       len = strlen(_PATH_CP) + strlen(argv[i]) +
+                           strlen(argv[argc - 1]) + 20;
+                       bp = xmalloc(len);
+                       (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
+                           iamrecursive ? " -r" : "", pflag ? " -p" : "",
+                           argv[i], argv[argc - 1]);
+                       if (verbose_mode)
+                               fprintf(stderr, "Executing: %s\n", bp);
+                       if (system(bp))
+                               ++errs;
+                       (void) xfree(bp);
+                       continue;
+               }
+               *src++ = 0;
+               if (*src == 0)
+                       src = ".";
+               if ((host = strchr(argv[i], '@')) == NULL) {
+                       host = argv[i];
+                       suser = NULL;
+               } else {
+                       *host++ = 0;
+                       suser = argv[i];
+                       if (*suser == '\0')
+                               suser = pwd->pw_name;
+                       else if (!okname(suser))
+                               continue;
+               }
+               host = cleanhostname(host);
+               len = strlen(src) + CMDNEEDS + 20;
+               bp = xmalloc(len);
+               (void) snprintf(bp, len, "%s -f %s", cmd, src);
+               if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) {
+                       (void) xfree(bp);
+                       ++errs;
+                       continue;
+               }
+               xfree(bp);
+               sink(1, argv + argc - 1);
+               (void) close(remin);
+               remin = remout = -1;
+       }
+}
+
+void
+source(argc, argv)
+       int argc;
+       char *argv[];
+{
+       struct stat stb;
+       static BUF buffer;
+       BUF *bp;
+       off_t i, amt, result;
+       int fd, haderr, indx;
+       char *last, *name, buf[2048];
+       int len;
+
+       for (indx = 0; indx < argc; ++indx) {
+               name = argv[indx];
+               statbytes = 0;
+               len = strlen(name);
+               while (len > 1 && name[len-1] == '/')
+                       name[--len] = '\0';
+               if (strchr(name, '\n') != NULL) {
+                       run_err("%s: skipping, filename contains a newline",
+                           name);
+                       goto next;
+               }
+               if ((fd = open(name, O_RDONLY, 0)) < 0)
+                       goto syserr;
+               if (fstat(fd, &stb) < 0) {
+syserr:                        run_err("%s: %s", name, strerror(errno));
+                       goto next;
+               }
+               switch (stb.st_mode & S_IFMT) {
+               case S_IFREG:
+                       break;
+               case S_IFDIR:
+                       if (iamrecursive) {
+                               rsource(name, &stb);
+                               goto next;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       run_err("%s: not a regular file", name);
+                       goto next;
+               }
+               if ((last = strrchr(name, '/')) == NULL)
+                       last = name;
+               else
+                       ++last;
+               curfile = last;
+               if (pflag) {
+                       /*
+                        * Make it compatible with possible future
+                        * versions expecting microseconds.
+                        */
+                       (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
+                           (u_long) stb.st_mtime,
+                           (u_long) stb.st_atime);
+                       (void) atomicio(write, remout, buf, strlen(buf));
+                       if (response() < 0)
+                               goto next;
+               }
+#define        FILEMODEMASK    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+#ifdef HAVE_LONG_LONG_INT
+               snprintf(buf, sizeof buf, "C%04o %lld %s\n",
+                   (u_int) (stb.st_mode & FILEMODEMASK),
+                   (long long) stb.st_size, last);
+#else
+               /* XXX: Handle integer overflow? */
+               snprintf(buf, sizeof buf, "C%04o %lu %s\n",
+                   (u_int) (stb.st_mode & FILEMODEMASK),
+                   (u_long) stb.st_size, last);
+#endif
+
+               if (verbose_mode) {
+                       fprintf(stderr, "Sending file modes: %s", buf);
+                       fflush(stderr);
+               }
+               (void) atomicio(write, remout, buf, strlen(buf));
+               if (response() < 0)
+                       goto next;
+               if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
+next:                  (void) close(fd);
+                       continue;
+               }
+               if (showprogress) {
+                       totalbytes = stb.st_size;
+                       progressmeter(-1);
+               }
+               /* Keep writing after an error so that we stay sync'd up. */
+               for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
+                       amt = bp->cnt;
+                       if (i + amt > stb.st_size)
+                               amt = stb.st_size - i;
+                       if (!haderr) {
+                               result = atomicio(read, fd, bp->buf, amt);
+                               if (result != amt)
+                                       haderr = result >= 0 ? EIO : errno;
+                       }
+                       if (haderr)
+                               (void) atomicio(write, remout, bp->buf, amt);
+                       else {
+                               result = atomicio(write, remout, bp->buf, amt);
+                               if (result != amt)
+                                       haderr = result >= 0 ? EIO : errno;
+                               statbytes += result;
+                       }
+               }
+               if (showprogress)
+                       progressmeter(1);
+
+               if (close(fd) < 0 && !haderr)
+                       haderr = errno;
+               if (!haderr)
+                       (void) atomicio(write, remout, "", 1);
+               else
+                       run_err("%s: %s", name, strerror(haderr));
+               (void) response();
+       }
+}
+
+void
+rsource(name, statp)
+       char *name;
+       struct stat *statp;
+{
+       DIR *dirp;
+       struct dirent *dp;
+       char *last, *vect[1], path[1100];
+
+       if (!(dirp = opendir(name))) {
+               run_err("%s: %s", name, strerror(errno));
+               return;
+       }
+       last = strrchr(name, '/');
+       if (last == 0)
+               last = name;
+       else
+               last++;
+       if (pflag) {
+               (void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",
+                   (u_long) statp->st_mtime,
+                   (u_long) statp->st_atime);
+               (void) atomicio(write, remout, path, strlen(path));
+               if (response() < 0) {
+                       closedir(dirp);
+                       return;
+               }
+       }
+       (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
+           (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
+       if (verbose_mode)
+               fprintf(stderr, "Entering directory: %s", path);
+       (void) atomicio(write, remout, path, strlen(path));
+       if (response() < 0) {
+               closedir(dirp);
+               return;
+       }
+       while ((dp = readdir(dirp)) != NULL) {
+               if (dp->d_ino == 0)
+                       continue;
+               if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+                       continue;
+               if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
+                       run_err("%s/%s: name too long", name, dp->d_name);
+                       continue;
+               }
+               (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
+               vect[0] = path;
+               source(1, vect);
+       }
+       (void) closedir(dirp);
+       (void) atomicio(write, remout, "E\n", 2);
+       (void) response();
+}
+
+void
+sink(argc, argv)
+       int argc;
+       char *argv[];
+{
+       static BUF buffer;
+       struct stat stb;
+       enum {
+               YES, NO, DISPLAYED
+       } wrerr;
+       BUF *bp;
+       off_t i, j;
+       int amt, count, exists, first, mask, mode, ofd, omode;
+       off_t size;
+       int setimes, targisdir, wrerrno = 0;
+       char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
+       struct timeval tv[2];
+
+#define        atime   tv[0]
+#define        mtime   tv[1]
+#define        SCREWUP(str)    do { why = str; goto screwup; } while (0)
+
+       setimes = targisdir = 0;
+       mask = umask(0);
+       if (!pflag)
+               (void) umask(mask);
+       if (argc != 1) {
+               run_err("ambiguous target");
+               exit(1);
+       }
+       targ = *argv;
+       if (targetshouldbedirectory)
+               verifydir(targ);
+
+       (void) atomicio(write, remout, "", 1);
+       if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
+               targisdir = 1;
+       for (first = 1;; first = 0) {
+               cp = buf;
+               if (atomicio(read, remin, cp, 1) <= 0)
+                       return;
+               if (*cp++ == '\n')
+                       SCREWUP("unexpected <newline>");
+               do {
+                       if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
+                               SCREWUP("lost connection");
+                       *cp++ = ch;
+               } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
+               *cp = 0;
+
+               if (buf[0] == '\01' || buf[0] == '\02') {
+                       if (iamremote == 0)
+                               (void) atomicio(write, STDERR_FILENO,
+                                   buf + 1, strlen(buf + 1));
+                       if (buf[0] == '\02')
+                               exit(1);
+                       ++errs;
+                       continue;
+               }
+               if (buf[0] == 'E') {
+                       (void) atomicio(write, remout, "", 1);
+                       return;
+               }
+               if (ch == '\n')
+                       *--cp = 0;
+
+               cp = buf;
+               if (*cp == 'T') {
+                       setimes++;
+                       cp++;
+                       mtime.tv_sec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != ' ')
+                               SCREWUP("mtime.sec not delimited");
+                       mtime.tv_usec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != ' ')
+                               SCREWUP("mtime.usec not delimited");
+                       atime.tv_sec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != ' ')
+                               SCREWUP("atime.sec not delimited");
+                       atime.tv_usec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != '\0')
+                               SCREWUP("atime.usec not delimited");
+                       (void) atomicio(write, remout, "", 1);
+                       continue;
+               }
+               if (*cp != 'C' && *cp != 'D') {
+                       /*
+                        * Check for the case "rcp remote:foo\* local:bar".
+                        * In this case, the line "No match." can be returned
+                        * by the shell before the rcp command on the remote is
+                        * executed so the ^Aerror_message convention isn't
+                        * followed.
+                        */
+                       if (first) {
+                               run_err("%s", cp);
+                               exit(1);
+                       }
+                       SCREWUP("expected control record");
+               }
+               mode = 0;
+               for (++cp; cp < buf + 5; cp++) {
+                       if (*cp < '0' || *cp > '7')
+                               SCREWUP("bad mode");
+                       mode = (mode << 3) | (*cp - '0');
+               }
+               if (*cp++ != ' ')
+                       SCREWUP("mode not delimited");
+
+               for (size = 0; isdigit(*cp);)
+                       size = size * 10 + (*cp++ - '0');
+               if (*cp++ != ' ')
+                       SCREWUP("size not delimited");
+               if (targisdir) {
+                       static char *namebuf;
+                       static int cursize;
+                       size_t need;
+
+                       need = strlen(targ) + strlen(cp) + 250;
+                       if (need > cursize) {
+                               if (namebuf)
+                                       xfree(namebuf);
+                               namebuf = xmalloc(need);
+                               cursize = need;
+                       }
+                       (void) snprintf(namebuf, need, "%s%s%s", targ,
+                           *targ ? "/" : "", cp);
+                       np = namebuf;
+               } else
+                       np = targ;
+               curfile = cp;
+               exists = stat(np, &stb) == 0;
+               if (buf[0] == 'D') {
+                       int mod_flag = pflag;
+                       if (exists) {
+                               if (!S_ISDIR(stb.st_mode)) {
+                                       errno = ENOTDIR;
+                                       goto bad;
+                               }
+                               if (pflag)
+                                       (void) chmod(np, mode);
+                       } else {
+                               /* Handle copying from a read-only
+                                  directory */
+                               mod_flag = 1;
+                               if (mkdir(np, mode | S_IRWXU) < 0)
+                                       goto bad;
+                       }
+                       vect[0] = xstrdup(np);
+                       sink(1, vect);
+                       if (setimes) {
+                               setimes = 0;
+                               if (utimes(vect[0], tv) < 0)
+                                       run_err("%s: set times: %s",
+                                           vect[0], strerror(errno));
+                       }
+                       if (mod_flag)
+                               (void) chmod(vect[0], mode);
+                       if (vect[0])
+                               xfree(vect[0]);
+                       continue;
+               }
+               omode = mode;
+               mode |= S_IWRITE;
+               if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
+bad:                   run_err("%s: %s", np, strerror(errno));
+                       continue;
+               }
+               (void) atomicio(write, remout, "", 1);
+               if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
+                       (void) close(ofd);
+                       continue;
+               }
+               cp = bp->buf;
+               wrerr = NO;
+
+               if (showprogress) {
+                       totalbytes = size;
+                       progressmeter(-1);
+               }
+               statbytes = 0;
+               for (count = i = 0; i < size; i += 4096) {
+                       amt = 4096;
+                       if (i + amt > size)
+                               amt = size - i;
+                       count += amt;
+                       do {
+                               j = read(remin, cp, amt);
+                               if (j == -1 && (errno == EINTR ||
+                                   errno == EAGAIN)) {
+                                       continue;
+                               } else if (j <= 0) {
+                                       run_err("%s", j ? strerror(errno) :
+                                           "dropped connection");
+                                       exit(1);
+                               }
+                               amt -= j;
+                               cp += j;
+                               statbytes += j;
+                       } while (amt > 0);
+                       if (count == bp->cnt) {
+                               /* Keep reading so we stay sync'd up. */
+                               if (wrerr == NO) {
+                                       j = atomicio(write, ofd, bp->buf, count);
+                                       if (j != count) {
+                                               wrerr = YES;
+                                               wrerrno = j >= 0 ? EIO : errno;
+                                       }
+                               }
+                               count = 0;
+                               cp = bp->buf;
+                       }
+               }
+               if (showprogress)
+                       progressmeter(1);
+               if (count != 0 && wrerr == NO &&
+                   (j = atomicio(write, ofd, bp->buf, count)) != count) {
+                       wrerr = YES;
+                       wrerrno = j >= 0 ? EIO : errno;
+               }
+               if (ftruncate(ofd, size)) {
+                       run_err("%s: truncate: %s", np, strerror(errno));
+                       wrerr = DISPLAYED;
+               }
+               if (pflag) {
+                       if (exists || omode != mode)
+#ifdef HAVE_FCHMOD
+                               if (fchmod(ofd, omode))
+#else /* HAVE_FCHMOD */
+                               if (chmod(np, omode))
+#endif /* HAVE_FCHMOD */
+                                       run_err("%s: set mode: %s",
+                                           np, strerror(errno));
+               } else {
+                       if (!exists && omode != mode)
+#ifdef HAVE_FCHMOD
+                               if (fchmod(ofd, omode & ~mask))
+#else /* HAVE_FCHMOD */
+                               if (chmod(np, omode & ~mask))
+#endif /* HAVE_FCHMOD */
+                                       run_err("%s: set mode: %s",
+                                           np, strerror(errno));
+               }
+               if (close(ofd) == -1) {
+                       wrerr = YES;
+                       wrerrno = errno;
+               }
+               (void) response();
+               if (setimes && wrerr == NO) {
+                       setimes = 0;
+                       if (utimes(np, tv) < 0) {
+                               run_err("%s: set times: %s",
+                                   np, strerror(errno));
+                               wrerr = DISPLAYED;
+                       }
+               }
+               switch (wrerr) {
+               case YES:
+                       run_err("%s: %s", np, strerror(wrerrno));
+                       break;
+               case NO:
+                       (void) atomicio(write, remout, "", 1);
+                       break;
+               case DISPLAYED:
+                       break;
+               }
+       }
+screwup:
+       run_err("protocol error: %s", why);
+       exit(1);
+}
+
+int
+response()
+{
+       char ch, *cp, resp, rbuf[2048];
+
+       if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
+               lostconn(0);
+
+       cp = rbuf;
+       switch (resp) {
+       case 0:         /* ok */
+               return (0);
+       default:
+               *cp++ = resp;
+               /* FALLTHROUGH */
+       case 1:         /* error, followed by error msg */
+       case 2:         /* fatal error, "" */
+               do {
+                       if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
+                               lostconn(0);
+                       *cp++ = ch;
+               } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
+
+               if (!iamremote)
+                       (void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf);
+               ++errs;
+               if (resp == 1)
+                       return (-1);
+               exit(1);
+       }
+       /* NOTREACHED */
+}
+
+void
+usage()
+{
+       (void) fprintf(stderr,
+           "usage: scp [-pqrvBC46] [-F config] [-S ssh] [-P port] [-c cipher] [-i identity]\n"
+           "           [-o option] f1 f2\n"
+           "   or: scp [options] f1 ... fn directory\n");
+       exit(1);
+}
+
+void
+run_err(const char *fmt,...)
+{
+       static FILE *fp;
+       va_list ap;
+
+       ++errs;
+       if (fp == NULL && !(fp = fdopen(remout, "w")))
+               return;
+       (void) fprintf(fp, "%c", 0x01);
+       (void) fprintf(fp, "scp: ");
+       va_start(ap, fmt);
+       (void) vfprintf(fp, fmt, ap);
+       va_end(ap);
+       (void) fprintf(fp, "\n");
+       (void) fflush(fp);
+
+       if (!iamremote) {
+               va_start(ap, fmt);
+               vfprintf(stderr, fmt, ap);
+               va_end(ap);
+               fprintf(stderr, "\n");
+       }
+}
+
+void
+verifydir(cp)
+       char *cp;
+{
+       struct stat stb;
+
+       if (!stat(cp, &stb)) {
+               if (S_ISDIR(stb.st_mode))
+                       return;
+               errno = ENOTDIR;
+       }
+       run_err("%s: %s", cp, strerror(errno));
+       exit(1);
+}
+
+int
+okname(cp0)
+       char *cp0;
+{
+       int c;
+       char *cp;
+
+       cp = cp0;
+       do {
+               c = (int)*cp;
+               if (c & 0200)
+                       goto bad;
+               if (!isalpha(c) && !isdigit(c) &&
+                   c != '_' && c != '-' && c != '.' && c != '+')
+                       goto bad;
+       } while (*++cp);
+       return (1);
+
+bad:   fprintf(stderr, "%s: invalid user name\n", cp0);
+       return (0);
+}
+
+BUF *
+allocbuf(bp, fd, blksize)
+       BUF *bp;
+       int fd, blksize;
+{
+       size_t size;
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+       struct stat stb;
+
+       if (fstat(fd, &stb) < 0) {
+               run_err("fstat: %s", strerror(errno));
+               return (0);
+       }
+       if (stb.st_blksize == 0)
+               size = blksize;
+       else
+               size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %
+                   stb.st_blksize;
+#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */
+       size = blksize;
+#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
+       if (bp->cnt >= size)
+               return (bp);
+       if (bp->buf == NULL)
+               bp->buf = xmalloc(size);
+       else
+               bp->buf = xrealloc(bp->buf, size);
+       memset(bp->buf, 0, size);
+       bp->cnt = size;
+       return (bp);
+}
+
+void
+lostconn(signo)
+       int signo;
+{
+       if (!iamremote)
+               write(STDERR_FILENO, "lost connection\n", 16);
+       if (signo)
+               _exit(1);
+       else
+               exit(1);
+}
+
+static void
+updateprogressmeter(int ignore)
+{
+       int save_errno = errno;
+
+       progressmeter(0);
+       signal(SIGALRM, updateprogressmeter);
+       alarm(PROGRESSTIME);
+       errno = save_errno;
+}
+
+static int
+foregroundproc(void)
+{
+       static pid_t pgrp = -1;
+       int ctty_pgrp;
+
+       if (pgrp == -1)
+               pgrp = getpgrp();
+
+#ifdef HAVE_TCGETPGRP
+       return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 &&
+               ctty_pgrp == pgrp);
+#else
+       return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
+                ctty_pgrp == pgrp));
+#endif
+}
+
+void
+progressmeter(int flag)
+{
+       static const char prefixes[] = " KMGTP";
+       static struct timeval lastupdate;
+       static off_t lastsize;
+       struct timeval now, td, wait;
+       off_t cursize, abbrevsize;
+       double elapsed;
+       int ratio, barlength, i, remaining;
+       char buf[256];
+
+       if (flag == -1) {
+               (void) gettimeofday(&start, (struct timezone *) 0);
+               lastupdate = start;
+               lastsize = 0;
+       }
+       if (foregroundproc() == 0)
+               return;
+
+       (void) gettimeofday(&now, (struct timezone *) 0);
+       cursize = statbytes;
+       if (totalbytes != 0) {
+               ratio = 100.0 * cursize / totalbytes;
+               ratio = MAX(ratio, 0);
+               ratio = MIN(ratio, 100);
+       } else
+               ratio = 100;
+
+       snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
+
+       barlength = getttywidth() - 51;
+       barlength = (barlength <= MAX_BARLENGTH)?barlength:MAX_BARLENGTH;
+       if (barlength > 0) {
+               i = barlength * ratio / 100;
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                        "|%.*s%*s|", i, BAR, barlength - i, "");
+       }
+       i = 0;
+       abbrevsize = cursize;
+       while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
+               i++;
+               abbrevsize >>= 10;
+       }
+       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5lu %c%c ",
+           (unsigned long) abbrevsize, prefixes[i],
+           prefixes[i] == ' ' ? ' ' : 'B');
+
+       timersub(&now, &lastupdate, &wait);
+       if (cursize > lastsize) {
+               lastupdate = now;
+               lastsize = cursize;
+               if (wait.tv_sec >= STALLTIME) {
+                       start.tv_sec += wait.tv_sec;
+                       start.tv_usec += wait.tv_usec;
+               }
+               wait.tv_sec = 0;
+       }
+       timersub(&now, &start, &td);
+       elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
+
+       if (flag != 1 &&
+           (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) {
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                   "   --:-- ETA");
+       } else if (wait.tv_sec >= STALLTIME) {
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                   " - stalled -");
+       } else {
+               if (flag != 1)
+                       remaining = (int)(totalbytes / (statbytes / elapsed) -
+                           elapsed);
+               else
+                       remaining = elapsed;
+
+               i = remaining / 3600;
+               if (i)
+                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                           "%2d:", i);
+               else
+                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                           "   ");
+               i = remaining % 3600;
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                   "%02d:%02d%s", i / 60, i % 60,
+                   (flag != 1) ? " ETA" : "    ");
+       }
+       atomicio(write, fileno(stdout), buf, strlen(buf));
+
+       if (flag == -1) {
+               mysignal(SIGALRM, updateprogressmeter);
+               alarm(PROGRESSTIME);
+       } else if (flag == 1) {
+               alarm(0);
+               atomicio(write, fileno(stdout), "\n", 1);
+               statbytes = 0;
+       }
+}
+
+int
+getttywidth(void)
+{
+       struct winsize winsize;
+
+       if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
+               return (winsize.ws_col ? winsize.ws_col : 80);
+       else
+               return (80);
+}
diff --git a/openssh/servconf.c b/openssh/servconf.c
new file mode 100644 (file)
index 0000000..e914d4c
--- /dev/null
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: servconf.c,v 1.91 2001/11/12 18:17:07 markus Exp $");
+
+#if defined(KRB4) || defined(KRB5)
+#include <krb.h>
+#endif
+#ifdef AFS
+#include <kafs.h>
+#endif
+
+#include "ssh.h"
+#include "log.h"
+#include "servconf.h"
+#include "xmalloc.h"
+#include "compat.h"
+#include "pathnames.h"
+#include "tildexpand.h"
+#include "misc.h"
+#include "cipher.h"
+#include "kex.h"
+#include "mac.h"
+
+static void add_listen_addr(ServerOptions *, char *, u_short);
+static void add_one_listen_addr(ServerOptions *, char *, u_short);
+
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+extern int IPv4or6;
+
+/* Initializes the server options to their default values. */
+
+void
+initialize_server_options(ServerOptions *options)
+{
+       memset(options, 0, sizeof(*options));
+
+       /* Portable-specific options */
+       options->pam_authentication_via_kbd_int = -1;
+
+       /* Standard Options */
+       options->num_ports = 0;
+       options->ports_from_cmdline = 0;
+       options->listen_addrs = NULL;
+       options->num_host_key_files = 0;
+       options->pid_file = NULL;
+       options->server_key_bits = -1;
+       options->login_grace_time = -1;
+       options->key_regeneration_time = -1;
+       options->permit_root_login = PERMIT_NOT_SET;
+       options->ignore_rhosts = -1;
+       options->ignore_user_known_hosts = -1;
+       options->print_motd = -1;
+       options->print_lastlog = -1;
+       options->x11_forwarding = -1;
+       options->x11_display_offset = -1;
+       options->xauth_location = NULL;
+       options->strict_modes = -1;
+       options->keepalives = -1;
+       options->log_facility = (SyslogFacility) - 1;
+       options->log_level = (LogLevel) - 1;
+       options->rhosts_authentication = -1;
+       options->rhosts_rsa_authentication = -1;
+       options->hostbased_authentication = -1;
+       options->hostbased_uses_name_from_packet_only = -1;
+       options->rsa_authentication = -1;
+       options->pubkey_authentication = -1;
+#if defined(KRB4) || defined(KRB5)
+       options->kerberos_authentication = -1;
+       options->kerberos_or_local_passwd = -1;
+       options->kerberos_ticket_cleanup = -1;
+#endif
+#if defined(AFS) || defined(KRB5)
+       options->kerberos_tgt_passing = -1;
+#endif
+#ifdef AFS
+       options->afs_token_passing = -1;
+#endif
+       options->password_authentication = -1;
+       options->kbd_interactive_authentication = -1;
+       options->challenge_response_authentication = -1;
+       options->permit_empty_passwd = -1;
+       options->use_login = -1;
+       options->allow_tcp_forwarding = -1;
+       options->num_allow_users = 0;
+       options->num_deny_users = 0;
+       options->num_allow_groups = 0;
+       options->num_deny_groups = 0;
+       options->ciphers = NULL;
+       options->macs = NULL;
+       options->protocol = SSH_PROTO_UNKNOWN;
+       options->gateway_ports = -1;
+       options->num_subsystems = 0;
+       options->max_startups_begin = -1;
+       options->max_startups_rate = -1;
+       options->max_startups = -1;
+       options->banner = NULL;
+       options->reverse_mapping_check = -1;
+       options->client_alive_interval = -1;
+       options->client_alive_count_max = -1;
+       options->authorized_keys_file = NULL;
+       options->authorized_keys_file2 = NULL;
+}
+
+void
+fill_default_server_options(ServerOptions *options)
+{
+       /* Portable-specific options */
+       if (options->pam_authentication_via_kbd_int == -1)
+               options->pam_authentication_via_kbd_int = 0;
+
+       /* Standard Options */
+       if (options->protocol == SSH_PROTO_UNKNOWN)
+               options->protocol = SSH_PROTO_1|SSH_PROTO_2;
+       if (options->num_host_key_files == 0) {
+               /* fill default hostkeys for protocols */
+               if (options->protocol & SSH_PROTO_1)
+                       options->host_key_files[options->num_host_key_files++] = _PATH_HOST_KEY_FILE;
+               if (options->protocol & SSH_PROTO_2)
+                       options->host_key_files[options->num_host_key_files++] = _PATH_HOST_DSA_KEY_FILE;
+       }
+       if (options->num_ports == 0)
+               options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
+       if (options->listen_addrs == NULL)
+               add_listen_addr(options, NULL, 0);
+       if (options->pid_file == NULL)
+               options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
+       if (options->server_key_bits == -1)
+               options->server_key_bits = 768;
+       if (options->login_grace_time == -1)
+               options->login_grace_time = 600;
+       if (options->key_regeneration_time == -1)
+               options->key_regeneration_time = 3600;
+       if (options->permit_root_login == PERMIT_NOT_SET)
+               options->permit_root_login = PERMIT_YES;
+       if (options->ignore_rhosts == -1)
+               options->ignore_rhosts = 1;
+       if (options->ignore_user_known_hosts == -1)
+               options->ignore_user_known_hosts = 0;
+       if (options->print_motd == -1)
+               options->print_motd = 1;
+       if (options->print_lastlog == -1)
+               options->print_lastlog = 1;
+       if (options->x11_forwarding == -1)
+               options->x11_forwarding = 0;
+       if (options->x11_display_offset == -1)
+               options->x11_display_offset = 10;
+#ifdef _PATH_XAUTH
+       if (options->xauth_location == NULL)
+               options->xauth_location = _PATH_XAUTH;
+#endif
+       if (options->strict_modes == -1)
+               options->strict_modes = 1;
+       if (options->keepalives == -1)
+               options->keepalives = 1;
+       if (options->log_facility == (SyslogFacility) (-1))
+               options->log_facility = SYSLOG_FACILITY_AUTH;
+       if (options->log_level == (LogLevel) (-1))
+               options->log_level = SYSLOG_LEVEL_INFO;
+       if (options->rhosts_authentication == -1)
+               options->rhosts_authentication = 0;
+       if (options->rhosts_rsa_authentication == -1)
+               options->rhosts_rsa_authentication = 0;
+       if (options->hostbased_authentication == -1)
+               options->hostbased_authentication = 0;
+       if (options->hostbased_uses_name_from_packet_only == -1)
+               options->hostbased_uses_name_from_packet_only = 0;
+       if (options->rsa_authentication == -1)
+               options->rsa_authentication = 1;
+       if (options->pubkey_authentication == -1)
+               options->pubkey_authentication = 1;
+#if defined(KRB4) || defined(KRB5)
+       if (options->kerberos_authentication == -1)
+               options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
+       if (options->kerberos_or_local_passwd == -1)
+               options->kerberos_or_local_passwd = 1;
+       if (options->kerberos_ticket_cleanup == -1)
+               options->kerberos_ticket_cleanup = 1;
+#endif
+#if defined(AFS) || defined(KRB5)
+       if (options->kerberos_tgt_passing == -1)
+               options->kerberos_tgt_passing = 0;
+#endif
+#ifdef AFS     
+       if (options->afs_token_passing == -1)
+               options->afs_token_passing = k_hasafs();
+#endif
+       if (options->password_authentication == -1)
+               options->password_authentication = 1;
+       if (options->kbd_interactive_authentication == -1)
+               options->kbd_interactive_authentication = 0;
+       if (options->challenge_response_authentication == -1)
+               options->challenge_response_authentication = 1;
+       if (options->permit_empty_passwd == -1)
+               options->permit_empty_passwd = 0;
+       if (options->use_login == -1)
+               options->use_login = 0;
+       if (options->allow_tcp_forwarding == -1)
+               options->allow_tcp_forwarding = 1;
+       if (options->gateway_ports == -1)
+               options->gateway_ports = 0;
+       if (options->max_startups == -1)
+               options->max_startups = 10;
+       if (options->max_startups_rate == -1)
+               options->max_startups_rate = 100;               /* 100% */
+       if (options->max_startups_begin == -1)
+               options->max_startups_begin = options->max_startups;
+       if (options->reverse_mapping_check == -1)
+               options->reverse_mapping_check = 0;
+       if (options->client_alive_interval == -1)
+               options->client_alive_interval = 0;  
+       if (options->client_alive_count_max == -1)
+               options->client_alive_count_max = 3;
+       if (options->authorized_keys_file2 == NULL) {
+               /* authorized_keys_file2 falls back to authorized_keys_file */
+               if (options->authorized_keys_file != NULL)
+                       options->authorized_keys_file2 = options->authorized_keys_file;
+               else
+                       options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
+       }
+       if (options->authorized_keys_file == NULL)
+               options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
+}
+
+/* Keyword tokens. */
+typedef enum {
+       sBadOption,             /* == unknown option */
+       /* Portable-specific options */
+       sPAMAuthenticationViaKbdInt,
+       /* Standard Options */
+       sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
+       sPermitRootLogin, sLogFacility, sLogLevel,
+       sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
+#if defined(KRB4) || defined(KRB5)
+       sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
+#endif
+#if defined(AFS) || defined(KRB5)
+       sKerberosTgtPassing,
+#endif
+#ifdef AFS
+       sAFSTokenPassing,
+#endif
+       sChallengeResponseAuthentication,
+       sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
+       sPrintMotd, sPrintLastLog, sIgnoreRhosts,
+       sX11Forwarding, sX11DisplayOffset,
+       sStrictModes, sEmptyPasswd, sKeepAlives,
+       sUseLogin, sAllowTcpForwarding,
+       sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+       sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
+       sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
+       sBanner, sReverseMappingCheck, sHostbasedAuthentication,
+       sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 
+       sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+       sDeprecated 
+} ServerOpCodes;
+
+/* Textual representation of the tokens. */
+static struct {
+       const char *name;
+       ServerOpCodes opcode;
+} keywords[] = {
+       /* Portable-specific options */
+       { "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt },
+       /* Standard Options */
+       { "port", sPort },
+       { "hostkey", sHostKeyFile },
+       { "hostdsakey", sHostKeyFile },                                 /* alias */
+       { "pidfile", sPidFile },
+       { "serverkeybits", sServerKeyBits },
+       { "logingracetime", sLoginGraceTime },
+       { "keyregenerationinterval", sKeyRegenerationTime },
+       { "permitrootlogin", sPermitRootLogin },
+       { "syslogfacility", sLogFacility },
+       { "loglevel", sLogLevel },
+       { "rhostsauthentication", sRhostsAuthentication },
+       { "rhostsrsaauthentication", sRhostsRSAAuthentication },
+       { "hostbasedauthentication", sHostbasedAuthentication },
+       { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
+       { "rsaauthentication", sRSAAuthentication },
+       { "pubkeyauthentication", sPubkeyAuthentication },
+       { "dsaauthentication", sPubkeyAuthentication },                 /* alias */
+#if defined(KRB4) || defined(KRB5)
+       { "kerberosauthentication", sKerberosAuthentication },
+       { "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
+       { "kerberosticketcleanup", sKerberosTicketCleanup },
+#endif
+#if defined(AFS) || defined(KRB5)
+       { "kerberostgtpassing", sKerberosTgtPassing },
+#endif
+#ifdef AFS
+       { "afstokenpassing", sAFSTokenPassing },
+#endif
+       { "passwordauthentication", sPasswordAuthentication },
+       { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
+       { "challengeresponseauthentication", sChallengeResponseAuthentication },
+       { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
+       { "checkmail", sDeprecated },
+       { "listenaddress", sListenAddress },
+       { "printmotd", sPrintMotd },
+       { "printlastlog", sPrintLastLog },
+       { "ignorerhosts", sIgnoreRhosts },
+       { "ignoreuserknownhosts", sIgnoreUserKnownHosts },
+       { "x11forwarding", sX11Forwarding },
+       { "x11displayoffset", sX11DisplayOffset },
+       { "xauthlocation", sXAuthLocation },
+       { "strictmodes", sStrictModes },
+       { "permitemptypasswords", sEmptyPasswd },
+       { "uselogin", sUseLogin },
+       { "keepalive", sKeepAlives },
+       { "allowtcpforwarding", sAllowTcpForwarding },
+       { "allowusers", sAllowUsers },
+       { "denyusers", sDenyUsers },
+       { "allowgroups", sAllowGroups },
+       { "denygroups", sDenyGroups },
+       { "ciphers", sCiphers },
+       { "macs", sMacs },
+       { "protocol", sProtocol },
+       { "gatewayports", sGatewayPorts },
+       { "subsystem", sSubsystem },
+       { "maxstartups", sMaxStartups },
+       { "banner", sBanner },
+       { "reversemappingcheck", sReverseMappingCheck },
+       { "clientaliveinterval", sClientAliveInterval },
+       { "clientalivecountmax", sClientAliveCountMax },
+       { "authorizedkeysfile", sAuthorizedKeysFile },
+       { "authorizedkeysfile2", sAuthorizedKeysFile2 },
+       { NULL, 0 }
+};
+
+/*
+ * Returns the number of the token pointed to by cp or sBadOption.
+ */
+
+static ServerOpCodes
+parse_token(const char *cp, const char *filename,
+           int linenum)
+{
+       u_int i;
+
+       for (i = 0; keywords[i].name; i++)
+               if (strcasecmp(cp, keywords[i].name) == 0)
+                       return keywords[i].opcode;
+
+       error("%s: line %d: Bad configuration option: %s",
+           filename, linenum, cp);
+       return sBadOption;
+}
+
+static void
+add_listen_addr(ServerOptions *options, char *addr, u_short port)
+{
+       int i;
+
+       if (options->num_ports == 0)
+               options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
+       if (port == 0)
+               for (i = 0; i < options->num_ports; i++)
+                       add_one_listen_addr(options, addr, options->ports[i]);
+       else
+               add_one_listen_addr(options, addr, port);
+}
+
+static void
+add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
+{
+       struct addrinfo hints, *ai, *aitop;
+       char strport[NI_MAXSERV];
+       int gaierr;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
+       snprintf(strport, sizeof strport, "%d", port);
+       if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
+               fatal("bad addr or host: %s (%s)",
+                   addr ? addr : "<NULL>",
+                   gai_strerror(gaierr));
+       for (ai = aitop; ai->ai_next; ai = ai->ai_next)
+               ;
+       ai->ai_next = options->listen_addrs;
+       options->listen_addrs = aitop;
+}
+
+/* Reads the server configuration file. */
+
+void
+read_server_config(ServerOptions *options, const char *filename)
+{
+       FILE *f;
+       char line[1024];
+       char *cp, **charptr, *arg, *p;
+       int linenum, *intptr, value;
+       int bad_options = 0;
+       ServerOpCodes opcode;
+       int i, n;
+
+       f = fopen(filename, "r");
+       if (!f) {
+               perror(filename);
+               exit(1);
+       }
+       linenum = 0;
+       while (fgets(line, sizeof(line), f)) {
+               linenum++;
+               cp = line;
+               arg = strdelim(&cp);
+               /* Ignore leading whitespace */
+               if (*arg == '\0')
+                       arg = strdelim(&cp);
+               if (!arg || !*arg || *arg == '#')
+                       continue;
+               intptr = NULL;
+               charptr = NULL;
+               opcode = parse_token(arg, filename, linenum);
+               switch (opcode) {
+               case sBadOption:
+                       bad_options++;
+                       continue;
+
+               /* Portable-specific options */
+               case sPAMAuthenticationViaKbdInt:
+                       intptr = &options->pam_authentication_via_kbd_int;
+                       goto parse_flag;
+
+               /* Standard Options */
+               case sPort:
+                       /* ignore ports from configfile if cmdline specifies ports */
+                       if (options->ports_from_cmdline)
+                               continue;
+                       if (options->listen_addrs != NULL)
+                               fatal("%s line %d: ports must be specified before "
+                                   "ListenAdress.", filename, linenum);
+                       if (options->num_ports >= MAX_PORTS)
+                               fatal("%s line %d: too many ports.",
+                                   filename, linenum);
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: missing port number.",
+                                   filename, linenum);
+                       options->ports[options->num_ports++] = a2port(arg);
+                       if (options->ports[options->num_ports-1] == 0)
+                               fatal("%s line %d: Badly formatted port number.",
+                                   filename, linenum);
+                       break;
+
+               case sServerKeyBits:
+                       intptr = &options->server_key_bits;
+parse_int:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: missing integer value.",
+                                   filename, linenum);
+                       value = atoi(arg);
+                       if (*intptr == -1)
+                               *intptr = value;
+                       break;
+
+               case sLoginGraceTime:
+                       intptr = &options->login_grace_time;
+parse_time:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: missing time value.",
+                                   filename, linenum);
+                       if ((value = convtime(arg)) == -1)
+                               fatal("%s line %d: invalid time value.",
+                                   filename, linenum);
+                       if (*intptr == -1)
+                               *intptr = value;
+                       break;
+
+               case sKeyRegenerationTime:
+                       intptr = &options->key_regeneration_time;
+                       goto parse_time;
+
+               case sListenAddress:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
+                               fatal("%s line %d: missing inet addr.",
+                                   filename, linenum);
+                       if (*arg == '[') {
+                               if ((p = strchr(arg, ']')) == NULL)
+                                       fatal("%s line %d: bad ipv6 inet addr usage.",
+                                           filename, linenum);
+                               arg++;
+                               memmove(p, p+1, strlen(p+1)+1);
+                       } else if (((p = strchr(arg, ':')) == NULL) ||
+                                   (strchr(p+1, ':') != NULL)) {
+                               add_listen_addr(options, arg, 0);
+                               break;
+                       }
+                       if (*p == ':') {
+                               u_short port;
+
+                               p++;
+                               if (*p == '\0')
+                                       fatal("%s line %d: bad inet addr:port usage.",
+                                           filename, linenum);
+                               else {
+                                       *(p-1) = '\0';
+                                       if ((port = a2port(p)) == 0)
+                                               fatal("%s line %d: bad port number.",
+                                                   filename, linenum);
+                                       add_listen_addr(options, arg, port);
+                               }
+                       } else if (*p == '\0')
+                               add_listen_addr(options, arg, 0);
+                       else
+                               fatal("%s line %d: bad inet addr usage.",
+                                   filename, linenum);
+                       break;
+
+               case sHostKeyFile:
+                       intptr = &options->num_host_key_files;
+                       if (*intptr >= MAX_HOSTKEYS)
+                               fatal("%s line %d: too many host keys specified (max %d).",
+                                   filename, linenum, MAX_HOSTKEYS);
+                       charptr = &options->host_key_files[*intptr];
+parse_filename:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: missing file name.",
+                                   filename, linenum);
+                       if (*charptr == NULL) {
+                               *charptr = tilde_expand_filename(arg, getuid());
+                               /* increase optional counter */
+                               if (intptr != NULL)
+                                       *intptr = *intptr + 1;
+                       }
+                       break;
+
+               case sPidFile:
+                       charptr = &options->pid_file;
+                       goto parse_filename;
+
+               case sPermitRootLogin:
+                       intptr = &options->permit_root_login;
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: missing yes/"
+                                   "without-password/forced-commands-only/no "
+                                   "argument.", filename, linenum);
+                       value = 0;      /* silence compiler */
+                       if (strcmp(arg, "without-password") == 0)
+                               value = PERMIT_NO_PASSWD;
+                       else if (strcmp(arg, "forced-commands-only") == 0)
+                               value = PERMIT_FORCED_ONLY;
+                       else if (strcmp(arg, "yes") == 0)
+                               value = PERMIT_YES;
+                       else if (strcmp(arg, "no") == 0)
+                               value = PERMIT_NO;
+                       else
+                               fatal("%s line %d: Bad yes/"
+                                   "without-password/forced-commands-only/no "
+                                   "argument: %s", filename, linenum, arg);
+                       if (*intptr == -1)
+                               *intptr = value;
+                       break;
+
+               case sIgnoreRhosts:
+                       intptr = &options->ignore_rhosts;
+parse_flag:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: missing yes/no argument.",
+                                   filename, linenum);
+                       value = 0;      /* silence compiler */
+                       if (strcmp(arg, "yes") == 0)
+                               value = 1;
+                       else if (strcmp(arg, "no") == 0)
+                               value = 0;
+                       else
+                               fatal("%s line %d: Bad yes/no argument: %s",
+                                       filename, linenum, arg);
+                       if (*intptr == -1)
+                               *intptr = value;
+                       break;
+
+               case sIgnoreUserKnownHosts:
+                       intptr = &options->ignore_user_known_hosts;
+                       goto parse_flag;
+
+               case sRhostsAuthentication:
+                       intptr = &options->rhosts_authentication;
+                       goto parse_flag;
+
+               case sRhostsRSAAuthentication:
+                       intptr = &options->rhosts_rsa_authentication;
+                       goto parse_flag;
+
+               case sHostbasedAuthentication:
+                       intptr = &options->hostbased_authentication;
+                       goto parse_flag;
+
+               case sHostbasedUsesNameFromPacketOnly:
+                       intptr = &options->hostbased_uses_name_from_packet_only;
+                       goto parse_flag;
+
+               case sRSAAuthentication:
+                       intptr = &options->rsa_authentication;
+                       goto parse_flag;
+
+               case sPubkeyAuthentication:
+                       intptr = &options->pubkey_authentication;
+                       goto parse_flag;
+#if defined(KRB4) || defined(KRB5)
+               case sKerberosAuthentication:
+                       intptr = &options->kerberos_authentication;
+                       goto parse_flag;
+
+               case sKerberosOrLocalPasswd:
+                       intptr = &options->kerberos_or_local_passwd;
+                       goto parse_flag;
+
+               case sKerberosTicketCleanup:
+                       intptr = &options->kerberos_ticket_cleanup;
+                       goto parse_flag;
+#endif
+#if defined(AFS) || defined(KRB5)
+               case sKerberosTgtPassing:
+                       intptr = &options->kerberos_tgt_passing;
+                       goto parse_flag;
+#endif
+#ifdef AFS
+               case sAFSTokenPassing:
+                       intptr = &options->afs_token_passing;
+                       goto parse_flag;
+#endif
+
+               case sPasswordAuthentication:
+                       intptr = &options->password_authentication;
+                       goto parse_flag;
+
+               case sKbdInteractiveAuthentication:
+                       intptr = &options->kbd_interactive_authentication;
+                       goto parse_flag;
+
+               case sChallengeResponseAuthentication:
+                       intptr = &options->challenge_response_authentication;
+                       goto parse_flag;
+
+               case sPrintMotd:
+                       intptr = &options->print_motd;
+                       goto parse_flag;
+
+               case sPrintLastLog:
+                       intptr = &options->print_lastlog;
+                       goto parse_flag;
+
+               case sX11Forwarding:
+                       intptr = &options->x11_forwarding;
+                       goto parse_flag;
+
+               case sX11DisplayOffset:
+                       intptr = &options->x11_display_offset;
+                       goto parse_int;
+
+               case sXAuthLocation:
+                       charptr = &options->xauth_location;
+                       goto parse_filename;
+
+               case sStrictModes:
+                       intptr = &options->strict_modes;
+                       goto parse_flag;
+
+               case sKeepAlives:
+                       intptr = &options->keepalives;
+                       goto parse_flag;
+
+               case sEmptyPasswd:
+                       intptr = &options->permit_empty_passwd;
+                       goto parse_flag;
+
+               case sUseLogin:
+                       intptr = &options->use_login;
+                       goto parse_flag;
+
+               case sGatewayPorts:
+                       intptr = &options->gateway_ports;
+                       goto parse_flag;
+
+               case sReverseMappingCheck:
+                       intptr = &options->reverse_mapping_check;
+                       goto parse_flag;
+
+               case sLogFacility:
+                       intptr = (int *) &options->log_facility;
+                       arg = strdelim(&cp);
+                       value = log_facility_number(arg);
+                       if (value == (SyslogFacility) - 1)
+                               fatal("%.200s line %d: unsupported log facility '%s'",
+                                   filename, linenum, arg ? arg : "<NONE>");
+                       if (*intptr == -1)
+                               *intptr = (SyslogFacility) value;
+                       break;
+
+               case sLogLevel:
+                       intptr = (int *) &options->log_level;
+                       arg = strdelim(&cp);
+                       value = log_level_number(arg);
+                       if (value == (LogLevel) - 1)
+                               fatal("%.200s line %d: unsupported log level '%s'",
+                                   filename, linenum, arg ? arg : "<NONE>");
+                       if (*intptr == -1)
+                               *intptr = (LogLevel) value;
+                       break;
+
+               case sAllowTcpForwarding:
+                       intptr = &options->allow_tcp_forwarding;
+                       goto parse_flag;
+
+               case sAllowUsers:
+                       while ((arg = strdelim(&cp)) && *arg != '\0') {
+                               if (options->num_allow_users >= MAX_ALLOW_USERS)
+                                       fatal("%s line %d: too many allow users.",
+                                           filename, linenum);
+                               options->allow_users[options->num_allow_users++] = xstrdup(arg);
+                       }
+                       break;
+
+               case sDenyUsers:
+                       while ((arg = strdelim(&cp)) && *arg != '\0') {
+                               if (options->num_deny_users >= MAX_DENY_USERS)
+                                       fatal( "%s line %d: too many deny users.",
+                                           filename, linenum);
+                               options->deny_users[options->num_deny_users++] = xstrdup(arg);
+                       }
+                       break;
+
+               case sAllowGroups:
+                       while ((arg = strdelim(&cp)) && *arg != '\0') {
+                               if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
+                                       fatal("%s line %d: too many allow groups.",
+                                           filename, linenum);
+                               options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
+                       }
+                       break;
+
+               case sDenyGroups:
+                       while ((arg = strdelim(&cp)) && *arg != '\0') {
+                               if (options->num_deny_groups >= MAX_DENY_GROUPS)
+                                       fatal("%s line %d: too many deny groups.",
+                                           filename, linenum);
+                               options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
+                       }
+                       break;
+
+               case sCiphers:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: Missing argument.", filename, linenum);
+                       if (!ciphers_valid(arg))
+                               fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
+                                   filename, linenum, arg ? arg : "<NONE>");
+                       if (options->ciphers == NULL)
+                               options->ciphers = xstrdup(arg);
+                       break;
+
+               case sMacs:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: Missing argument.", filename, linenum);
+                       if (!mac_valid(arg))
+                               fatal("%s line %d: Bad SSH2 mac spec '%s'.",
+                                   filename, linenum, arg ? arg : "<NONE>");
+                       if (options->macs == NULL)
+                               options->macs = xstrdup(arg);
+                       break;
+
+               case sProtocol:
+                       intptr = &options->protocol;
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: Missing argument.", filename, linenum);
+                       value = proto_spec(arg);
+                       if (value == SSH_PROTO_UNKNOWN)
+                               fatal("%s line %d: Bad protocol spec '%s'.",
+                                     filename, linenum, arg ? arg : "<NONE>");
+                       if (*intptr == SSH_PROTO_UNKNOWN)
+                               *intptr = value;
+                       break;
+
+               case sSubsystem:
+                       if(options->num_subsystems >= MAX_SUBSYSTEMS) {
+                               fatal("%s line %d: too many subsystems defined.",
+                                     filename, linenum);
+                       }
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: Missing subsystem name.",
+                                     filename, linenum);
+                       for (i = 0; i < options->num_subsystems; i++)
+                               if(strcmp(arg, options->subsystem_name[i]) == 0)
+                                       fatal("%s line %d: Subsystem '%s' already defined.",
+                                             filename, linenum, arg);
+                       options->subsystem_name[options->num_subsystems] = xstrdup(arg);
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: Missing subsystem command.",
+                                     filename, linenum);
+                       options->subsystem_command[options->num_subsystems] = xstrdup(arg);
+                       options->num_subsystems++;
+                       break;
+
+               case sMaxStartups:
+                       arg = strdelim(&cp);
+                       if (!arg || *arg == '\0')
+                               fatal("%s line %d: Missing MaxStartups spec.",
+                                     filename, linenum);
+                       if ((n = sscanf(arg, "%d:%d:%d",
+                           &options->max_startups_begin,
+                           &options->max_startups_rate,
+                           &options->max_startups)) == 3) {
+                               if (options->max_startups_begin >
+                                   options->max_startups ||
+                                   options->max_startups_rate > 100 ||
+                                   options->max_startups_rate < 1)
+                                       fatal("%s line %d: Illegal MaxStartups spec.",
+                                           filename, linenum);
+                       } else if (n != 1)
+                               fatal("%s line %d: Illegal MaxStartups spec.",
+                                   filename, linenum);
+                       else
+                               options->max_startups = options->max_startups_begin;
+                       break;
+
+               case sBanner:
+                       charptr = &options->banner;
+                       goto parse_filename;
+               /*
+                * These options can contain %X options expanded at
+                * connect time, so that you can specify paths like:
+                *
+                * AuthorizedKeysFile   /etc/ssh_keys/%u
+                */
+               case sAuthorizedKeysFile:
+               case sAuthorizedKeysFile2:
+                       charptr = (opcode == sAuthorizedKeysFile ) ?
+                           &options->authorized_keys_file :
+                           &options->authorized_keys_file2;
+                       goto parse_filename;
+
+               case sClientAliveInterval:
+                       intptr = &options->client_alive_interval;
+                       goto parse_time;
+
+               case sClientAliveCountMax:
+                       intptr = &options->client_alive_count_max;
+                       goto parse_int;
+
+               case sDeprecated:
+                       log("%s line %d: Deprecated option %s",
+                           filename, linenum, arg);
+                       while(arg)
+                           arg = strdelim(&cp);
+                       break;
+
+               default:
+                       fatal("%s line %d: Missing handler for opcode %s (%d)",
+                           filename, linenum, arg, opcode);
+               }
+               if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
+                       fatal("%s line %d: garbage at end of line; \"%.200s\".",
+                           filename, linenum, arg);
+       }
+       fclose(f);
+       if (bad_options > 0)
+               fatal("%s: terminating, %d bad configuration options",
+                   filename, bad_options);
+}
diff --git a/openssh/servconf.h b/openssh/servconf.h
new file mode 100644 (file)
index 0000000..2e10b1c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Definitions for server configuration data and for the functions reading it.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: servconf.h,v 1.49 2001/08/17 18:59:47 stevesk Exp $"); */
+
+#ifndef SERVCONF_H
+#define SERVCONF_H
+
+#define MAX_PORTS              256     /* Max # ports. */
+
+#define MAX_ALLOW_USERS                256     /* Max # users on allow list. */
+#define MAX_DENY_USERS         256     /* Max # users on deny list. */
+#define MAX_ALLOW_GROUPS       256     /* Max # groups on allow list. */
+#define MAX_DENY_GROUPS                256     /* Max # groups on deny list. */
+#define MAX_SUBSYSTEMS         256     /* Max # subsystems. */
+#define MAX_HOSTKEYS           256     /* Max # hostkeys. */
+
+/* permit_root_login */
+#define        PERMIT_NOT_SET          -1
+#define        PERMIT_NO               0
+#define        PERMIT_FORCED_ONLY      1
+#define        PERMIT_NO_PASSWD        2
+#define        PERMIT_YES              3
+
+
+typedef struct {
+       u_int num_ports;
+       u_int ports_from_cmdline;
+       u_short ports[MAX_PORTS];       /* Port number to listen on. */
+       char   *listen_addr;            /* Address on which the server listens. */
+       struct addrinfo *listen_addrs;  /* Addresses on which the server listens. */
+       char   *host_key_files[MAX_HOSTKEYS];   /* Files containing host keys. */
+       int     num_host_key_files;     /* Number of files for host keys. */
+       char   *pid_file;       /* Where to put our pid */
+       int     server_key_bits;/* Size of the server key. */
+       int     login_grace_time;       /* Disconnect if no auth in this time
+                                        * (sec). */
+       int     key_regeneration_time;  /* Server key lifetime (seconds). */
+       int     permit_root_login;      /* PERMIT_*, see above */
+       int     ignore_rhosts;  /* Ignore .rhosts and .shosts. */
+       int     ignore_user_known_hosts;        /* Ignore ~/.ssh/known_hosts
+                                                * for RhostsRsaAuth */
+       int     print_motd;     /* If true, print /etc/motd. */
+       int     print_lastlog;  /* If true, print lastlog */
+       int     x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
+       int     x11_display_offset;     /* What DISPLAY number to start
+                                        * searching at */
+       char   *xauth_location; /* Location of xauth program */
+       int     strict_modes;   /* If true, require string home dir modes. */
+       int     keepalives;     /* If true, set SO_KEEPALIVE. */
+       char   *ciphers;        /* Supported SSH2 ciphers. */
+       char   *macs;           /* Supported SSH2 macs. */
+       int     protocol;       /* Supported protocol versions. */
+       int     gateway_ports;  /* If true, allow remote connects to forwarded ports. */
+       SyslogFacility log_facility;    /* Facility for system logging. */
+       LogLevel log_level;     /* Level for system logging. */
+       int     rhosts_authentication;  /* If true, permit rhosts
+                                        * authentication. */
+       int     rhosts_rsa_authentication;      /* If true, permit rhosts RSA
+                                                * authentication. */
+       int     hostbased_authentication;       /* If true, permit ssh2 hostbased auth */
+       int     hostbased_uses_name_from_packet_only; /* experimental */
+       int     rsa_authentication;     /* If true, permit RSA authentication. */
+       int     pubkey_authentication;  /* If true, permit ssh2 pubkey authentication. */
+#if defined(KRB4) || defined(KRB5)
+       int     kerberos_authentication;        /* If true, permit Kerberos
+                                                * authentication. */
+       int     kerberos_or_local_passwd;       /* If true, permit kerberos
+                                                * and any other password
+                                                * authentication mechanism,
+                                                * such as SecurID or
+                                                * /etc/passwd */
+       int     kerberos_ticket_cleanup;        /* If true, destroy ticket
+                                                * file on logout. */
+#endif
+#if defined(AFS) || defined(KRB5)
+       int     kerberos_tgt_passing;   /* If true, permit Kerberos TGT
+                                        * passing. */
+#endif
+#ifdef AFS
+       int     afs_token_passing;      /* If true, permit AFS token passing. */
+#endif
+       int     password_authentication;        /* If true, permit password
+                                                * authentication. */
+       int     kbd_interactive_authentication; /* If true, permit */
+       int     challenge_response_authentication;
+       int     permit_empty_passwd;    /* If false, do not permit empty
+                                        * passwords. */
+       int     use_login;      /* If true, login(1) is used */
+       int     allow_tcp_forwarding;
+       u_int num_allow_users;
+       char   *allow_users[MAX_ALLOW_USERS];
+       u_int num_deny_users;
+       char   *deny_users[MAX_DENY_USERS];
+       u_int num_allow_groups;
+       char   *allow_groups[MAX_ALLOW_GROUPS];
+       u_int num_deny_groups;
+       char   *deny_groups[MAX_DENY_GROUPS];
+
+       u_int num_subsystems;
+       char   *subsystem_name[MAX_SUBSYSTEMS];
+       char   *subsystem_command[MAX_SUBSYSTEMS];
+
+       int     max_startups_begin;
+       int     max_startups_rate;
+       int     max_startups;
+       char   *banner;                 /* SSH-2 banner message */
+       int     reverse_mapping_check;  /* cross-check ip and dns */
+       int     client_alive_interval;  /*
+                                        * poke the client this often to 
+                                        * see if it's still there 
+                                        */
+       int     client_alive_count_max; /*
+                                        * If the client is unresponsive
+                                        * for this many intervals above,
+                                        * disconnect the session 
+                                        */
+
+       char   *authorized_keys_file;   /* File containing public keys */
+       char   *authorized_keys_file2;
+       int     pam_authentication_via_kbd_int;
+
+}       ServerOptions;
+
+void    initialize_server_options(ServerOptions *);
+void    read_server_config(ServerOptions *, const char *);
+void    fill_default_server_options(ServerOptions *);
+
+#endif                         /* SERVCONF_H */
diff --git a/openssh/serverloop.c b/openssh/serverloop.c
new file mode 100644 (file)
index 0000000..0da805f
--- /dev/null
@@ -0,0 +1,1009 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Server main loop for handling the interactive session.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * SSH2 support by Markus Friedl.
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: serverloop.c,v 1.83 2001/11/09 18:59:23 markus Exp $");
+
+#include "xmalloc.h"
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "sshpty.h"
+#include "channels.h"
+#include "compat.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "auth.h"
+#include "session.h"
+#include "dispatch.h"
+#include "auth-options.h"
+#include "serverloop.h"
+#include "misc.h"
+#include "kex.h"
+
+extern ServerOptions options;
+
+/* XXX */
+extern Kex *xxx_kex;
+static Authctxt *xxx_authctxt;
+
+static Buffer stdin_buffer;    /* Buffer for stdin data. */
+static Buffer stdout_buffer;   /* Buffer for stdout data. */
+static Buffer stderr_buffer;   /* Buffer for stderr data. */
+static int fdin;               /* Descriptor for stdin (for writing) */
+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 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. */
+static int fdin_is_tty = 0;    /* fdin points to a tty. */
+static int connection_in;      /* Connection to client (input). */
+static int connection_out;     /* Connection to client (output). */
+static int connection_closed = 0;      /* Connection to client closed. */
+static u_int buffer_high;      /* "Soft" max buffer size. */
+static int client_alive_timeouts = 0;
+
+/*
+ * This SIGCHLD kludge is used to detect when the child exits.  The server
+ * will exit after that, as soon as forwarded connections have terminated.
+ */
+
+static volatile int child_terminated;  /* The child has terminated. */
+
+/* prototypes */
+static void server_init_dispatch(void);
+
+static void
+sigchld_handler(int sig)
+{
+       int save_errno = errno;
+       debug("Received SIGCHLD.");
+       child_terminated = 1;
+       mysignal(SIGCHLD, sigchld_handler);
+       errno = save_errno;
+}
+
+/*
+ * Make packets from buffered stderr data, and buffer it for sending
+ * to the client.
+ */
+static void
+make_packets_from_stderr_data(void)
+{
+       int len;
+
+       /* Send buffered stderr data to the client. */
+       while (buffer_len(&stderr_buffer) > 0 &&
+           packet_not_very_much_data_to_write()) {
+               len = buffer_len(&stderr_buffer);
+               if (packet_is_interactive()) {
+                       if (len > 512)
+                               len = 512;
+               } else {
+                       /* Keep the packets at reasonable size. */
+                       if (len > packet_get_maxsize())
+                               len = packet_get_maxsize();
+               }
+               packet_start(SSH_SMSG_STDERR_DATA);
+               packet_put_string(buffer_ptr(&stderr_buffer), len);
+               packet_send();
+               buffer_consume(&stderr_buffer, len);
+               stderr_bytes += len;
+       }
+}
+
+/*
+ * Make packets from buffered stdout data, and buffer it for sending to the
+ * client.
+ */
+static void
+make_packets_from_stdout_data(void)
+{
+       int len;
+
+       /* Send buffered stdout data to the client. */
+       while (buffer_len(&stdout_buffer) > 0 &&
+           packet_not_very_much_data_to_write()) {
+               len = buffer_len(&stdout_buffer);
+               if (packet_is_interactive()) {
+                       if (len > 512)
+                               len = 512;
+               } else {
+                       /* Keep the packets at reasonable size. */
+                       if (len > packet_get_maxsize())
+                               len = packet_get_maxsize();
+               }
+               packet_start(SSH_SMSG_STDOUT_DATA);
+               packet_put_string(buffer_ptr(&stdout_buffer), len);
+               packet_send();
+               buffer_consume(&stdout_buffer, len);
+               stdout_bytes += len;
+       }
+}
+
+static void
+client_alive_check(void)
+{
+       int id;
+
+       /* timeout, check to see how many we have had */
+       if (++client_alive_timeouts > options.client_alive_count_max)
+               packet_disconnect("Timeout, your session not responding.");
+
+       id = channel_find_open();
+       if (id == -1)
+               packet_disconnect("No open channels after timeout!");
+       /*
+        * send a bogus channel request with "wantreply",
+        * we should get back a failure
+        */
+       channel_request_start(id, "keepalive@openssh.com", 1);
+       packet_send();
+}
+
+/*
+ * Sleep in select() until we can do something.  This will initialize the
+ * select masks.  Upon return, the masks will indicate which descriptors
+ * have data or can accept data.  Optionally, a maximum time can be specified
+ * for the duration of the wait (0 = infinite).
+ */
+static void
+wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
+    int *nallocp, u_int max_time_milliseconds)
+{
+       struct timeval tv, *tvp;
+       int ret;
+       int client_alive_scheduled = 0;
+
+       /*
+        * if using client_alive, set the max timeout accordingly, 
+        * and indicate that this particular timeout was for client
+        * alive by setting the client_alive_scheduled flag.
+        *
+        * this could be randomized somewhat to make traffic
+        * analysis more difficult, but we're not doing it yet.  
+        */
+       if (compat20 &&
+           max_time_milliseconds == 0 && options.client_alive_interval) {
+               client_alive_scheduled = 1;
+               max_time_milliseconds = options.client_alive_interval * 1000;
+       }
+
+       /* Allocate and update select() masks for channel descriptors. */
+       channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
+
+       if (compat20) {
+#if 0
+               /* wrong: bad condition XXX */
+               if (channel_not_very_much_buffered_data())
+#endif
+               FD_SET(connection_in, *readsetp);
+       } else {
+               /*
+                * Read packets from the client unless we have too much
+                * buffered stdin or channel data.
+                */
+               if (buffer_len(&stdin_buffer) < buffer_high &&
+                   channel_not_very_much_buffered_data())
+                       FD_SET(connection_in, *readsetp);
+               /*
+                * If there is not too much data already buffered going to
+                * the client, try to get some more data from the program.
+                */
+               if (packet_not_very_much_data_to_write()) {
+                       if (!fdout_eof)
+                               FD_SET(fdout, *readsetp);
+                       if (!fderr_eof)
+                               FD_SET(fderr, *readsetp);
+               }
+               /*
+                * If we have buffered data, try to write some of that data
+                * to the program.
+                */
+               if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
+                       FD_SET(fdin, *writesetp);
+       }
+
+       /*
+        * If we have buffered packet data going to the client, mark that
+        * descriptor.
+        */
+       if (packet_have_data_to_write())
+               FD_SET(connection_out, *writesetp);
+
+       /*
+        * If child has terminated and there is enough buffer space to read
+        * from it, then read as much as is available and exit.
+        */
+       if (child_terminated && packet_not_very_much_data_to_write())
+               if (max_time_milliseconds == 0 || client_alive_scheduled)
+                       max_time_milliseconds = 100;
+
+       if (max_time_milliseconds == 0)
+               tvp = NULL;
+       else {
+               tv.tv_sec = max_time_milliseconds / 1000;
+               tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
+               tvp = &tv;
+       }
+       if (tvp!=NULL)
+               debug3("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
+
+       /* Wait for something to happen, or the timeout to expire. */
+       ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
+
+       if (ret == -1) {
+               memset(*readsetp, 0, *nallocp);
+               memset(*writesetp, 0, *nallocp);
+               if (errno != EINTR)
+                       error("select: %.100s", strerror(errno));
+       } else if (ret == 0 && client_alive_scheduled)
+               client_alive_check();
+}
+
+/*
+ * Processes input from the client and the program.  Input data is stored
+ * in buffers and processed later.
+ */
+static void
+process_input(fd_set * readset)
+{
+       int len;
+       char buf[16384];
+
+       /* Read and buffer any input data from the client. */
+       if (FD_ISSET(connection_in, readset)) {
+               len = read(connection_in, buf, sizeof(buf));
+               if (len == 0) {
+                       verbose("Connection closed by remote host.");
+                       connection_closed = 1;
+                       if (compat20)
+                               return;
+                       fatal_cleanup();
+               } else if (len < 0) {
+                       if (errno != EINTR && errno != EAGAIN) {
+                               verbose("Read error from remote host: %.100s", strerror(errno));
+                               fatal_cleanup();
+                       }
+               } else {
+                       /* Buffer any received data. */
+                       packet_process_incoming(buf, len);
+               }
+       }
+       if (compat20)
+               return;
+
+       /* Read and buffer any available stdout data from the program. */
+       if (!fdout_eof && FD_ISSET(fdout, readset)) {
+               len = read(fdout, buf, sizeof(buf));
+               if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+                       /* do nothing */
+               } else if (len <= 0) {
+                       fdout_eof = 1;
+               } else {
+                       buffer_append(&stdout_buffer, buf, len);
+                       fdout_bytes += len;
+               }
+       }
+       /* Read and buffer any available stderr data from the program. */
+       if (!fderr_eof && FD_ISSET(fderr, readset)) {
+               len = read(fderr, buf, sizeof(buf));
+               if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+                       /* do nothing */
+               } else if (len <= 0) {
+                       fderr_eof = 1;
+               } else {
+                       buffer_append(&stderr_buffer, buf, len);
+               }
+       }
+}
+
+/*
+ * Sends data from internal buffers to client program stdin.
+ */
+static void
+process_output(fd_set * writeset)
+{
+       struct termios tio;
+       u_char *data;
+       u_int dlen;
+       int len;
+
+       /* Write buffered data to program stdin. */
+       if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
+               data = buffer_ptr(&stdin_buffer);
+               dlen = buffer_len(&stdin_buffer);
+               len = write(fdin, data, dlen);
+               if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+                       /* do nothing */
+               } else if (len <= 0) {
+#ifdef USE_PIPES
+                       close(fdin);
+#else
+                       if (fdin != fdout)
+                               close(fdin);
+                       else
+                               shutdown(fdin, SHUT_WR); /* We will no longer send. */
+#endif
+                       fdin = -1;
+               } else {
+                       /* Successful write. */
+                       if (fdin_is_tty && dlen >= 1 && data[0] != '\r' &&
+                           tcgetattr(fdin, &tio) == 0 &&
+                           !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
+                               /*
+                                * Simulate echo to reduce the impact of
+                                * traffic analysis
+                                */
+                               packet_send_ignore(len);
+                               packet_send();
+                       }
+                       /* Consume the data from the buffer. */
+                       buffer_consume(&stdin_buffer, len);
+                       /* Update the count of bytes written to the program. */
+                       stdin_bytes += len;
+               }
+       }
+       /* Send any buffered packet data to the client. */
+       if (FD_ISSET(connection_out, writeset))
+               packet_write_poll();
+}
+
+/*
+ * Wait until all buffered output has been sent to the client.
+ * This is used when the program terminates.
+ */
+static void
+drain_output(void)
+{
+       /* Send any buffered stdout data to the client. */
+       if (buffer_len(&stdout_buffer) > 0) {
+               packet_start(SSH_SMSG_STDOUT_DATA);
+               packet_put_string(buffer_ptr(&stdout_buffer),
+                                 buffer_len(&stdout_buffer));
+               packet_send();
+               /* Update the count of sent bytes. */
+               stdout_bytes += buffer_len(&stdout_buffer);
+       }
+       /* Send any buffered stderr data to the client. */
+       if (buffer_len(&stderr_buffer) > 0) {
+               packet_start(SSH_SMSG_STDERR_DATA);
+               packet_put_string(buffer_ptr(&stderr_buffer),
+                                 buffer_len(&stderr_buffer));
+               packet_send();
+               /* Update the count of sent bytes. */
+               stderr_bytes += buffer_len(&stderr_buffer);
+       }
+       /* Wait until all buffered data has been written to the client. */
+       packet_write_wait();
+}
+
+static void
+process_buffered_input_packets(void)
+{
+       dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
+}
+
+/*
+ * Performs the interactive session.  This handles data transmission between
+ * the client and the program.  Note that the notion of stdin, stdout, and
+ * stderr in this function is sort of reversed: this function writes to
+ * stdin (of the child program), and reads from stdout and stderr (of the
+ * child program).
+ */
+void
+server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
+{
+       fd_set *readset = NULL, *writeset = NULL;
+       int max_fd = 0, nalloc = 0;
+       int wait_status;        /* Status returned by wait(). */
+       pid_t wait_pid;         /* pid returned by wait(). */
+       int waiting_termination = 0;    /* Have displayed waiting close message. */
+       u_int max_time_milliseconds;
+       u_int previous_stdout_buffer_bytes;
+       u_int stdout_buffer_bytes;
+       int type;
+
+       debug("Entering interactive session.");
+
+       /* Initialize the SIGCHLD kludge. */
+       child_terminated = 0;
+       mysignal(SIGCHLD, sigchld_handler);
+
+       /* Initialize our global variables. */
+       fdin = fdin_arg;
+       fdout = fdout_arg;
+       fderr = fderr_arg;
+
+       /* nonblocking IO */
+       set_nonblock(fdin);
+       set_nonblock(fdout);
+       /* we don't have stderr for interactive terminal sessions, see below */
+       if (fderr != -1)
+               set_nonblock(fderr);
+
+       if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
+               fdin_is_tty = 1;
+
+       connection_in = packet_get_connection_in();
+       connection_out = packet_get_connection_out();
+
+       previous_stdout_buffer_bytes = 0;
+
+       /* Set approximate I/O buffer size. */
+       if (packet_is_interactive())
+               buffer_high = 4096;
+       else
+               buffer_high = 64 * 1024;
+
+#if 0
+       /* Initialize max_fd to the maximum of the known file descriptors. */
+       max_fd = MAX(connection_in, connection_out);
+       max_fd = MAX(max_fd, fdin);
+       max_fd = MAX(max_fd, fdout);
+       if (fderr != -1)
+               max_fd = MAX(max_fd, fderr);
+#endif
+
+       /* Initialize Initialize buffers. */
+       buffer_init(&stdin_buffer);
+       buffer_init(&stdout_buffer);
+       buffer_init(&stderr_buffer);
+
+       /*
+        * If we have no separate fderr (which is the case when we have a pty
+        * - there we cannot make difference between data sent to stdout and
+        * stderr), indicate that we have seen an EOF from stderr.  This way
+        * we don\'t need to check the descriptor everywhere.
+        */
+       if (fderr == -1)
+               fderr_eof = 1;
+
+       server_init_dispatch();
+
+       /* Main loop of the server for the interactive session mode. */
+       for (;;) {
+
+               /* Process buffered packets from the client. */
+               process_buffered_input_packets();
+
+               /*
+                * If we have received eof, and there is no more pending
+                * input data, cause a real eof by closing fdin.
+                */
+               if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
+#ifdef USE_PIPES
+                       close(fdin);
+#else
+                       if (fdin != fdout)
+                               close(fdin);
+                       else
+                               shutdown(fdin, SHUT_WR); /* We will no longer send. */
+#endif
+                       fdin = -1;
+               }
+               /* Make packets from buffered stderr data to send to the client. */
+               make_packets_from_stderr_data();
+
+               /*
+                * Make packets from buffered stdout data to send to the
+                * client. If there is very little to send, this arranges to
+                * not send them now, but to wait a short while to see if we
+                * are getting more data. This is necessary, as some systems
+                * wake up readers from a pty after each separate character.
+                */
+               max_time_milliseconds = 0;
+               stdout_buffer_bytes = buffer_len(&stdout_buffer);
+               if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
+                   stdout_buffer_bytes != previous_stdout_buffer_bytes) {
+                       /* try again after a while */
+                       max_time_milliseconds = 10;
+               } else {
+                       /* Send it now. */
+                       make_packets_from_stdout_data();
+               }
+               previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
+
+               /* Send channel data to the client. */
+               if (packet_not_very_much_data_to_write())
+                       channel_output_poll();
+
+               /*
+                * Bail out of the loop if the program has closed its output
+                * descriptors, and we have no more data to send to the
+                * client, and there is no pending buffered data.
+                */
+               if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
+                   buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
+                       if (!channel_still_open())
+                               break;
+                       if (!waiting_termination) {
+                               const char *s = "Waiting for forwarded connections to terminate...\r\n";
+                               char *cp;
+                               waiting_termination = 1;
+                               buffer_append(&stderr_buffer, s, strlen(s));
+
+                               /* Display list of open channels. */
+                               cp = channel_open_message();
+                               buffer_append(&stderr_buffer, cp, strlen(cp));
+                               xfree(cp);
+                       }
+               }
+               max_fd = MAX(connection_in, connection_out);
+               max_fd = MAX(max_fd, fdin);
+               max_fd = MAX(max_fd, fdout);
+               max_fd = MAX(max_fd, fderr);
+
+               /* Sleep in select() until we can do something. */
+               wait_until_can_do_something(&readset, &writeset, &max_fd,
+                   &nalloc, max_time_milliseconds);
+
+               /* Process any channel events. */
+               channel_after_select(readset, writeset);
+
+               /* Process input from the client and from program stdout/stderr. */
+               process_input(readset);
+
+               /* Process output to the client and to program stdin. */
+               process_output(writeset);
+       }
+       if (readset)
+               xfree(readset);
+       if (writeset)
+               xfree(writeset);
+
+       /* Cleanup and termination code. */
+
+       /* Wait until all output has been sent to the client. */
+       drain_output();
+
+       debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
+             stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
+
+       /* Free and clear the buffers. */
+       buffer_free(&stdin_buffer);
+       buffer_free(&stdout_buffer);
+       buffer_free(&stderr_buffer);
+
+       /* Close the file descriptors. */
+       if (fdout != -1)
+               close(fdout);
+       fdout = -1;
+       fdout_eof = 1;
+       if (fderr != -1)
+               close(fderr);
+       fderr = -1;
+       fderr_eof = 1;
+       if (fdin != -1)
+               close(fdin);
+       fdin = -1;
+
+       channel_free_all();
+
+       /* We no longer want our SIGCHLD handler to be called. */
+       mysignal(SIGCHLD, SIG_DFL);
+
+       wait_pid = waitpid(-1, &wait_status, child_terminated ? WNOHANG : 0);
+       if (wait_pid == -1)
+               packet_disconnect("wait: %.100s", strerror(errno));
+       else if (wait_pid != pid)
+               error("Strange, wait returned pid %d, expected %d",
+                   wait_pid, pid);
+
+       /* Check if it exited normally. */
+       if (WIFEXITED(wait_status)) {
+               /* Yes, normal exit.  Get exit status and send it to the client. */
+               debug("Command exited with status %d.", WEXITSTATUS(wait_status));
+               packet_start(SSH_SMSG_EXITSTATUS);
+               packet_put_int(WEXITSTATUS(wait_status));
+               packet_send();
+               packet_write_wait();
+
+               /*
+                * Wait for exit confirmation.  Note that there might be
+                * other packets coming before it; however, the program has
+                * already died so we just ignore them.  The client is
+                * supposed to respond with the confirmation when it receives
+                * the exit status.
+                */
+               do {
+                       int plen;
+                       type = packet_read(&plen);
+               }
+               while (type != SSH_CMSG_EXIT_CONFIRMATION);
+
+               debug("Received exit confirmation.");
+               return;
+       }
+       /* Check if the program terminated due to a signal. */
+       if (WIFSIGNALED(wait_status))
+               packet_disconnect("Command terminated on signal %d.",
+                                 WTERMSIG(wait_status));
+
+       /* Some weird exit cause.  Just exit. */
+       packet_disconnect("wait returned status %04x.", wait_status);
+       /* NOTREACHED */
+}
+
+static void
+collect_children(void)
+{
+       pid_t pid;
+       sigset_t oset, nset;
+       int status;
+
+       /* block SIGCHLD while we check for dead children */
+       sigemptyset(&nset);
+       sigaddset(&nset, SIGCHLD);
+       sigprocmask(SIG_BLOCK, &nset, &oset);
+       if (child_terminated) {
+               while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+                       session_close_by_pid(pid, status);
+               child_terminated = 0;
+       }
+       sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+void
+server_loop2(Authctxt *authctxt)
+{
+       fd_set *readset = NULL, *writeset = NULL;
+       int rekeying = 0, max_fd, nalloc = 0;
+
+       debug("Entering interactive session for SSH2.");
+
+       mysignal(SIGCHLD, sigchld_handler);
+       child_terminated = 0;
+       connection_in = packet_get_connection_in();
+       connection_out = packet_get_connection_out();
+
+       max_fd = MAX(connection_in, connection_out);
+       xxx_authctxt = authctxt;
+
+       server_init_dispatch();
+
+       for (;;) {
+               process_buffered_input_packets();
+
+               rekeying = (xxx_kex != NULL && !xxx_kex->done);
+
+               if (!rekeying && packet_not_very_much_data_to_write())
+                       channel_output_poll();
+               wait_until_can_do_something(&readset, &writeset, &max_fd,
+                   &nalloc, 0);
+
+               collect_children();
+               if (!rekeying)
+                       channel_after_select(readset, writeset);
+               process_input(readset);
+               if (connection_closed)
+                       break;
+               process_output(writeset);
+       }
+       collect_children();
+
+       if (readset)
+               xfree(readset);
+       if (writeset)
+               xfree(writeset);
+
+       /* free all channels, no more reads and writes */
+       channel_free_all();
+
+       /* free remaining sessions, e.g. remove wtmp entries */
+       session_destroy_all();
+}
+
+static void
+server_input_channel_failure(int type, int plen, void *ctxt)
+{
+       debug("Got CHANNEL_FAILURE for keepalive");
+       /* 
+        * reset timeout, since we got a sane answer from the client.
+        * even if this was generated by something other than
+        * the bogus CHANNEL_REQUEST we send for keepalives.
+        */
+       client_alive_timeouts = 0; 
+}
+
+
+static void
+server_input_stdin_data(int type, int plen, void *ctxt)
+{
+       char *data;
+       u_int data_len;
+
+       /* Stdin data from the client.  Append it to the buffer. */
+       /* Ignore any data if the client has closed stdin. */
+       if (fdin == -1)
+               return;
+       data = packet_get_string(&data_len);
+       packet_integrity_check(plen, (4 + data_len), type);
+       buffer_append(&stdin_buffer, data, data_len);
+       memset(data, 0, data_len);
+       xfree(data);
+}
+
+static void
+server_input_eof(int type, int plen, void *ctxt)
+{
+       /*
+        * Eof from the client.  The stdin descriptor to the
+        * program will be closed when all buffered data has
+        * drained.
+        */
+       debug("EOF received for stdin.");
+       packet_integrity_check(plen, 0, type);
+       stdin_eof = 1;
+}
+
+static void
+server_input_window_size(int type, int plen, void *ctxt)
+{
+       int row = packet_get_int();
+       int col = packet_get_int();
+       int xpixel = packet_get_int();
+       int ypixel = packet_get_int();
+
+       debug("Window change received.");
+       packet_integrity_check(plen, 4 * 4, type);
+       if (fdin != -1)
+               pty_change_window_size(fdin, row, col, xpixel, ypixel);
+}
+
+static Channel *
+server_request_direct_tcpip(char *ctype)
+{
+       Channel *c;
+       int sock;
+       char *target, *originator;
+       int target_port, originator_port;
+
+       target = packet_get_string(NULL);
+       target_port = packet_get_int();
+       originator = packet_get_string(NULL);
+       originator_port = packet_get_int();
+       packet_done();
+
+       debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
+          originator, originator_port, target, target_port);
+
+       /* XXX check permission */
+       sock = channel_connect_to(target, target_port);
+       xfree(target);
+       xfree(originator);
+       if (sock < 0)
+               return NULL;
+       c = channel_new(ctype, SSH_CHANNEL_CONNECTING,
+           sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
+           CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
+       if (c == NULL) {
+               error("server_request_direct_tcpip: channel_new failed");
+               close(sock);
+       }
+       return c;
+}
+
+static Channel *
+server_request_session(char *ctype)
+{
+       Channel *c;
+
+       debug("input_session_request");
+       packet_done();
+       /*
+        * A server session has no fd to read or write until a
+        * CHANNEL_REQUEST for a shell is made, so we set the type to
+        * SSH_CHANNEL_LARVAL.  Additionally, a callback for handling all
+        * CHANNEL_REQUEST messages is registered.
+        */
+       c = channel_new(ctype, SSH_CHANNEL_LARVAL,
+           -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
+           0, xstrdup("server-session"), 1);
+       if (c == NULL) {
+               error("server_request_session: channel_new failed");
+               return NULL;
+       }
+       if (session_open(xxx_authctxt, c->self) != 1) {
+               debug("session open failed, free channel %d", c->self);
+               channel_free(c);
+               return NULL;
+       }
+       channel_register_callback(c->self, SSH2_MSG_CHANNEL_REQUEST,
+           session_input_channel_req, (void *)0);
+       channel_register_cleanup(c->self, session_close_by_channel);
+       return c;
+}
+
+static void
+server_input_channel_open(int type, int plen, void *ctxt)
+{
+       Channel *c = NULL;
+       char *ctype;
+       u_int len;
+       int rchan;
+       int rmaxpack;
+       int rwindow;
+
+       ctype = packet_get_string(&len);
+       rchan = packet_get_int();
+       rwindow = packet_get_int();
+       rmaxpack = packet_get_int();
+
+       debug("server_input_channel_open: ctype %s rchan %d win %d max %d",
+           ctype, rchan, rwindow, rmaxpack);
+
+       if (strcmp(ctype, "session") == 0) {
+               c = server_request_session(ctype);
+       } else if (strcmp(ctype, "direct-tcpip") == 0) {
+               c = server_request_direct_tcpip(ctype);
+       }
+       if (c != NULL) {
+               debug("server_input_channel_open: confirm %s", ctype);
+               c->remote_id = rchan;
+               c->remote_window = rwindow;
+               c->remote_maxpacket = rmaxpack;
+               if (c->type != SSH_CHANNEL_CONNECTING) {
+                       packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+                       packet_put_int(c->remote_id);
+                       packet_put_int(c->self);
+                       packet_put_int(c->local_window);
+                       packet_put_int(c->local_maxpacket);
+                       packet_send();
+               }
+       } else {
+               debug("server_input_channel_open: failure %s", ctype);
+               packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+               packet_put_int(rchan);
+               packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
+               if (!(datafellows & SSH_BUG_OPENFAILURE)) {
+                       packet_put_cstring("open failed");
+                       packet_put_cstring("");
+               }
+               packet_send();
+       }
+       xfree(ctype);
+}
+
+static void
+server_input_global_request(int type, int plen, void *ctxt)
+{
+       char *rtype;
+       int want_reply;
+       int success = 0;
+
+       rtype = packet_get_string(NULL);
+       want_reply = packet_get_char();
+       debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
+
+       /* -R style forwarding */
+       if (strcmp(rtype, "tcpip-forward") == 0) {
+               struct passwd *pw;
+               char *listen_address;
+               u_short listen_port;
+
+               pw = auth_get_user();
+               if (pw == NULL)
+                       fatal("server_input_global_request: no user");
+               listen_address = packet_get_string(NULL); /* XXX currently ignored */
+               listen_port = (u_short)packet_get_int();
+               debug("server_input_global_request: tcpip-forward listen %s port %d",
+                   listen_address, listen_port);
+
+               /* check permissions */
+               if (!options.allow_tcp_forwarding ||
+                   no_port_forwarding_flag ||
+                   (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)) {
+                       success = 0;
+                       packet_send_debug("Server has disabled port forwarding.");
+               } else {
+                       /* Start listening on the port */
+                       success = channel_request_forwarding(
+                           listen_address, listen_port,
+                           /*unspec host_to_connect*/ "<unspec host>",
+                           /*unspec port_to_connect*/ 0,
+                           options.gateway_ports, /*remote*/ 1);
+               }
+               xfree(listen_address);
+       }
+       if (want_reply) {
+               packet_start(success ?
+                   SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
+               packet_send();
+               packet_write_wait();
+       }
+       xfree(rtype);
+}
+
+static void
+server_init_dispatch_20(void)
+{
+       debug("server_init_dispatch_20");
+       dispatch_init(&dispatch_protocol_error);
+       dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
+       dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
+       dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
+       dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
+       dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
+       dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
+       dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
+       dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
+       dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+       dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
+       /* client_alive */
+       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
+       /* rekeying */
+       dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
+}
+static void
+server_init_dispatch_13(void)
+{
+       debug("server_init_dispatch_13");
+       dispatch_init(NULL);
+       dispatch_set(SSH_CMSG_EOF, &server_input_eof);
+       dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data);
+       dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size);
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
+       dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
+       dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
+       dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
+       dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
+}
+static void
+server_init_dispatch_15(void)
+{
+       server_init_dispatch_13();
+       debug("server_init_dispatch_15");
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
+       dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
+}
+static void
+server_init_dispatch(void)
+{
+       if (compat20)
+               server_init_dispatch_20();
+       else if (compat13)
+               server_init_dispatch_13();
+       else
+               server_init_dispatch_15();
+}
diff --git a/openssh/serverloop.h b/openssh/serverloop.h
new file mode 100644 (file)
index 0000000..f419198
--- /dev/null
@@ -0,0 +1,27 @@
+/*     $OpenBSD: serverloop.h,v 1.5 2001/06/27 02:12:53 markus Exp $   */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Performs the interactive session.  This handles data transmission between
+ * the client and the program.  Note that the notion of stdin, stdout, and
+ * stderr in this function is sort of reversed: this function writes to stdin
+ * (of the child program), and reads from stdout and stderr (of the child
+ * program).
+ */
+#ifndef SERVERLOOP_H
+#define SERVERLOOP_H
+
+void    server_loop(pid_t, int, int, int);
+void    server_loop2(Authctxt *);
+
+#endif
diff --git a/openssh/session.c b/openssh/session.c
new file mode 100644 (file)
index 0000000..02c0c52
--- /dev/null
@@ -0,0 +1,2077 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * SSH2 support by Markus Friedl.
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: session.c,v 1.108 2001/10/11 13:45:21 markus Exp $");
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "sshpty.h"
+#include "packet.h"
+#include "buffer.h"
+#include "mpaux.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "channels.h"
+#include "bufaux.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "pathnames.h"
+#include "log.h"
+#include "servconf.h"
+#include "sshlogin.h"
+#include "serverloop.h"
+#include "canohost.h"
+#include "session.h"
+
+#ifdef WITH_IRIX_PROJECT
+#include <proj.h>
+#endif /* WITH_IRIX_PROJECT */
+#ifdef WITH_IRIX_JOBS
+#include <sys/resource.h>
+#endif
+#ifdef WITH_IRIX_AUDIT
+#include <sat.h>
+#endif /* WITH_IRIX_AUDIT */
+
+#if defined(HAVE_USERSEC_H)
+#include <usersec.h>
+#endif
+
+#ifdef HAVE_CYGWIN
+#include <windows.h>
+#include <sys/cygwin.h>
+#define is_winnt       (GetVersion() < 0x80000000)
+#endif
+
+/* AIX limits */
+#if defined(HAVE_GETUSERATTR) && !defined(S_UFSIZE_HARD) && defined(S_UFSIZE)
+# define S_UFSIZE_HARD  S_UFSIZE "_hard"
+# define S_UCPU_HARD  S_UCPU "_hard"
+# define S_UDATA_HARD  S_UDATA "_hard"
+# define S_USTACK_HARD  S_USTACK "_hard"
+# define S_URSS_HARD  S_URSS "_hard"
+# define S_UCORE_HARD  S_UCORE "_hard"
+# define S_UNOFILE_HARD        S_UNOFILE "_hard"
+#endif
+
+#ifdef _AIX
+# include <uinfo.h>
+#endif
+
+/* types */
+
+#define TTYSZ 64
+typedef struct Session Session;
+struct Session {
+       int     used;
+       int     self;
+       struct passwd *pw;
+       Authctxt *authctxt;
+       pid_t   pid;
+       /* tty */
+       char    *term;
+       int     ptyfd, ttyfd, ptymaster;
+       int     row, col, xpixel, ypixel;
+       char    tty[TTYSZ];
+       /* X11 */
+       char    *display;
+       int     screen;
+       char    *auth_proto;
+       char    *auth_data;
+       int     single_connection;
+       /* proto 2 */
+       int     chanid;
+       int     is_subsystem;
+};
+
+/* func */
+
+Session *session_new(void);
+void   session_set_fds(Session *, int, int, int);
+static void    session_pty_cleanup(void *);
+void   session_proctitle(Session *);
+int    session_setup_x11fwd(Session *);
+void   do_exec_pty(Session *, const char *);
+void   do_exec_no_pty(Session *, const char *);
+void   do_exec(Session *, const char *);
+void   do_login(Session *, const char *);
+#ifdef LOGIN_NEEDS_UTMPX
+static void    do_pre_login(Session *s);
+#endif
+void   do_child(Session *, const char *);
+void   do_motd(void);
+int    check_quietlogin(Session *, const char *);
+
+static void do_authenticated1(Authctxt *);
+static void do_authenticated2(Authctxt *);
+
+static void session_close(Session *);
+static int session_pty_req(Session *);
+
+/* import */
+extern ServerOptions options;
+extern char *__progname;
+extern int log_stderr;
+extern int debug_flag;
+extern u_int utmp_len;
+extern int startup_pipe;
+extern void destroy_sensitive_data(void);
+
+/* original command from peer. */
+const char *original_command = NULL;
+
+/* data */
+#define MAX_SESSIONS 10
+Session        sessions[MAX_SESSIONS];
+
+#ifdef WITH_AIXAUTHENTICATE
+char *aixloginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
+
+#ifdef HAVE_LOGIN_CAP
+static login_cap_t *lc;
+#endif
+
+void
+do_authenticated(Authctxt *authctxt)
+{
+       /*
+        * Cancel the alarm we set to limit the time taken for
+        * authentication.
+        */
+       alarm(0);
+       if (startup_pipe != -1) {
+               close(startup_pipe);
+               startup_pipe = -1;
+       }
+#if defined(HAVE_LOGIN_CAP) && defined(HAVE_PW_CLASS_IN_PASSWD)
+       if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {
+               error("unable to get login class");
+               return;
+       }
+#ifdef BSD_AUTH
+       if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) {
+               packet_disconnect("Approval failure for %s",
+                   authctxt->pw->pw_name);
+       }
+#endif
+#endif
+#ifdef WITH_AIXAUTHENTICATE
+       /* We don't have a pty yet, so just label the line as "ssh" */
+       if (loginsuccess(authctxt->user,
+           get_canonical_hostname(options.reverse_mapping_check),
+           "ssh", &aixloginmsg) < 0)
+               aixloginmsg = NULL;
+#endif /* WITH_AIXAUTHENTICATE */
+
+       /* setup the channel layer */
+       if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
+               channel_permit_all_opens();
+
+       if (compat20)
+               do_authenticated2(authctxt);
+       else
+               do_authenticated1(authctxt);
+
+       /* remove agent socket */
+       if (auth_get_socket_name())
+               auth_sock_cleanup_proc(authctxt->pw);
+#ifdef KRB4
+       if (options.kerberos_ticket_cleanup)
+               krb4_cleanup_proc(authctxt);
+#endif
+#ifdef KRB5
+       if (options.kerberos_ticket_cleanup)
+               krb5_cleanup_proc(authctxt);
+#endif
+}
+
+/*
+ * Prepares for an interactive session.  This is called after the user has
+ * been successfully authenticated.  During this message exchange, pseudo
+ * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
+ * are requested, etc.
+ */
+static void
+do_authenticated1(Authctxt *authctxt)
+{
+       Session *s;
+       char *command;
+       int success, type, plen, screen_flag;
+       int compression_level = 0, enable_compression_after_reply = 0;
+       u_int proto_len, data_len, dlen;
+
+       s = session_new();
+       s->authctxt = authctxt;
+       s->pw = authctxt->pw;
+
+       /*
+        * We stay in this loop until the client requests to execute a shell
+        * or a command.
+        */
+       for (;;) {
+               success = 0;
+
+               /* Get a packet from the client. */
+               type = packet_read(&plen);
+
+               /* Process the packet. */
+               switch (type) {
+               case SSH_CMSG_REQUEST_COMPRESSION:
+                       packet_integrity_check(plen, 4, type);
+                       compression_level = packet_get_int();
+                       if (compression_level < 1 || compression_level > 9) {
+                               packet_send_debug("Received illegal compression level %d.",
+                                    compression_level);
+                               break;
+                       }
+                       /* Enable compression after we have responded with SUCCESS. */
+                       enable_compression_after_reply = 1;
+                       success = 1;
+                       break;
+
+               case SSH_CMSG_REQUEST_PTY:
+                       success = session_pty_req(s);
+                       break;
+
+               case SSH_CMSG_X11_REQUEST_FORWARDING:
+                       s->auth_proto = packet_get_string(&proto_len);
+                       s->auth_data = packet_get_string(&data_len);
+
+                       screen_flag = packet_get_protocol_flags() &
+                           SSH_PROTOFLAG_SCREEN_NUMBER;
+                       debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
+
+                       if (packet_remaining() == 4) {
+                               if (!screen_flag)
+                                       debug2("Buggy client: "
+                                           "X11 screen flag missing");
+                               s->screen = packet_get_int();
+                       } else {
+                               s->screen = 0;
+                       }
+                       packet_done();
+                       success = session_setup_x11fwd(s);
+                       if (!success) {
+                               xfree(s->auth_proto);
+                               xfree(s->auth_data);
+                               s->auth_proto = NULL;
+                               s->auth_data = NULL;
+                       }
+                       break;
+
+               case SSH_CMSG_AGENT_REQUEST_FORWARDING:
+                       if (no_agent_forwarding_flag || compat13) {
+                               debug("Authentication agent forwarding not permitted for this authentication.");
+                               break;
+                       }
+                       debug("Received authentication agent forwarding request.");
+                       success = auth_input_request_forwarding(s->pw);
+                       break;
+
+               case SSH_CMSG_PORT_FORWARD_REQUEST:
+                       if (no_port_forwarding_flag) {
+                               debug("Port forwarding not permitted for this authentication.");
+                               break;
+                       }
+                       if (!options.allow_tcp_forwarding) {
+                               debug("Port forwarding not permitted.");
+                               break;
+                       }
+                       debug("Received TCP/IP port forwarding request.");
+                       channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
+                       success = 1;
+                       break;
+
+               case SSH_CMSG_MAX_PACKET_SIZE:
+                       if (packet_set_maxsize(packet_get_int()) > 0)
+                               success = 1;
+                       break;
+                       
+#if defined(AFS) || defined(KRB5)
+               case SSH_CMSG_HAVE_KERBEROS_TGT:
+                       if (!options.kerberos_tgt_passing) {
+                               verbose("Kerberos TGT passing disabled.");
+                       } else {
+                               char *kdata = packet_get_string(&dlen);
+                               packet_integrity_check(plen, 4 + dlen, type);
+                               
+                               /* XXX - 0x41, see creds_to_radix version */
+                               if (kdata[0] != 0x41) {
+#ifdef KRB5
+                                       krb5_data tgt;
+                                       tgt.data = kdata;
+                                       tgt.length = dlen;
+                                       
+                                       if (auth_krb5_tgt(s->authctxt, &tgt))
+                                               success = 1;
+                                       else
+                                               verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user);
+#endif /* KRB5 */
+                               } else {
+#ifdef AFS
+                                       if (auth_krb4_tgt(s->authctxt, kdata))
+                                               success = 1;
+                                       else
+                                               verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user);
+#endif /* AFS */
+                               }
+                               xfree(kdata);
+                       }
+                       break;
+#endif /* AFS || KRB5 */
+                       
+#ifdef AFS
+               case SSH_CMSG_HAVE_AFS_TOKEN:
+                       if (!options.afs_token_passing || !k_hasafs()) {
+                               verbose("AFS token passing disabled.");
+                       } else {
+                               /* Accept AFS token. */
+                               char *token = packet_get_string(&dlen);
+                               packet_integrity_check(plen, 4 + dlen, type);
+                               
+                               if (auth_afs_token(s->authctxt, token))
+                                       success = 1;
+                               else
+                                       verbose("AFS token refused for %.100s",
+                                           s->authctxt->user);
+                               xfree(token);
+                       }
+                       break;
+#endif /* AFS */
+
+               case SSH_CMSG_EXEC_SHELL:
+               case SSH_CMSG_EXEC_CMD:
+                       if (type == SSH_CMSG_EXEC_CMD) {
+                               command = packet_get_string(&dlen);
+                               debug("Exec command '%.500s'", command);
+                               do_exec(s, command);
+                               xfree(command);
+                       } else {
+                               do_exec(s, NULL);
+                       }
+                       packet_done();
+                       session_close(s);
+                       return;
+
+               default:
+                       /*
+                        * Any unknown messages in this phase are ignored,
+                        * and a failure message is returned.
+                        */
+                       log("Unknown packet type received after authentication: %d", type);
+               }
+               packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
+               packet_send();
+               packet_write_wait();
+
+               /* Enable compression now that we have replied if appropriate. */
+               if (enable_compression_after_reply) {
+                       enable_compression_after_reply = 0;
+                       packet_start_compression(compression_level);
+               }
+       }
+}
+
+/*
+ * This is called to fork and execute a command when we have no tty.  This
+ * will call do_child from the child, and server_loop from the parent after
+ * setting up file descriptors and such.
+ */
+void
+do_exec_no_pty(Session *s, const char *command)
+{
+       int pid;
+
+#ifdef USE_PIPES
+       int pin[2], pout[2], perr[2];
+       /* Allocate pipes for communicating with the program. */
+       if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
+               packet_disconnect("Could not create pipes: %.100s",
+                                 strerror(errno));
+#else /* USE_PIPES */
+       int inout[2], err[2];
+       /* Uses socket pairs to communicate with the program. */
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
+           socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
+               packet_disconnect("Could not create socket pairs: %.100s",
+                                 strerror(errno));
+#endif /* USE_PIPES */
+       if (s == NULL)
+               fatal("do_exec_no_pty: no session");
+
+       session_proctitle(s);
+
+#if defined(USE_PAM)
+       do_pam_session(s->pw->pw_name, NULL);
+       do_pam_setcred(1);
+       if (is_pam_password_change_required())
+               packet_disconnect("Password change required but no "
+                   "TTY available");
+#endif /* USE_PAM */
+
+       /* Fork the child. */
+       if ((pid = fork()) == 0) {
+               /* Child.  Reinitialize the log since the pid has changed. */
+               log_init(__progname, options.log_level, options.log_facility, log_stderr);
+
+               /*
+                * Create a new session and process group since the 4.4BSD
+                * setlogin() affects the entire process group.
+                */
+               if (setsid() < 0)
+                       error("setsid failed: %.100s", strerror(errno));
+
+#ifdef USE_PIPES
+               /*
+                * Redirect stdin.  We close the parent side of the socket
+                * pair, and make the child side the standard input.
+                */
+               close(pin[1]);
+               if (dup2(pin[0], 0) < 0)
+                       perror("dup2 stdin");
+               close(pin[0]);
+
+               /* Redirect stdout. */
+               close(pout[0]);
+               if (dup2(pout[1], 1) < 0)
+                       perror("dup2 stdout");
+               close(pout[1]);
+
+               /* Redirect stderr. */
+               close(perr[0]);
+               if (dup2(perr[1], 2) < 0)
+                       perror("dup2 stderr");
+               close(perr[1]);
+#else /* USE_PIPES */
+               /*
+                * Redirect stdin, stdout, and stderr.  Stdin and stdout will
+                * use the same socket, as some programs (particularly rdist)
+                * seem to depend on it.
+                */
+               close(inout[1]);
+               close(err[1]);
+               if (dup2(inout[0], 0) < 0)      /* stdin */
+                       perror("dup2 stdin");
+               if (dup2(inout[0], 1) < 0)      /* stdout.  Note: same socket as stdin. */
+                       perror("dup2 stdout");
+               if (dup2(err[0], 2) < 0)        /* stderr */
+                       perror("dup2 stderr");
+#endif /* USE_PIPES */
+
+               /* Do processing for the child (exec command etc). */
+               do_child(s, command);
+               /* NOTREACHED */
+       }
+#ifdef HAVE_CYGWIN
+       if (is_winnt)
+               cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+#endif
+       if (pid < 0)
+               packet_disconnect("fork failed: %.100s", strerror(errno));
+       s->pid = pid;
+       /* Set interactive/non-interactive mode. */
+       packet_set_interactive(s->display != NULL);
+#ifdef USE_PIPES
+       /* We are the parent.  Close the child sides of the pipes. */
+       close(pin[0]);
+       close(pout[1]);
+       close(perr[1]);
+
+       if (compat20) {
+               session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]);
+       } else {
+               /* Enter the interactive session. */
+               server_loop(pid, pin[1], pout[0], perr[0]);
+               /* server_loop has closed pin[1], pout[0], and perr[0]. */
+       }
+#else /* USE_PIPES */
+       /* We are the parent.  Close the child sides of the socket pairs. */
+       close(inout[0]);
+       close(err[0]);
+
+       /*
+        * Enter the interactive session.  Note: server_loop must be able to
+        * handle the case that fdin and fdout are the same.
+        */
+       if (compat20) {
+               session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
+       } else {
+               server_loop(pid, inout[1], inout[1], err[1]);
+               /* server_loop has closed inout[1] and err[1]. */
+       }
+#endif /* USE_PIPES */
+}
+
+/*
+ * This is called to fork and execute a command when we have a tty.  This
+ * will call do_child from the child, and server_loop from the parent after
+ * setting up file descriptors, controlling tty, updating wtmp, utmp,
+ * lastlog, and other such operations.
+ */
+void
+do_exec_pty(Session *s, const char *command)
+{
+       int fdout, ptyfd, ttyfd, ptymaster;
+       pid_t pid;
+
+       if (s == NULL)
+               fatal("do_exec_pty: no session");
+       ptyfd = s->ptyfd;
+       ttyfd = s->ttyfd;
+
+#if defined(USE_PAM)
+       do_pam_session(s->pw->pw_name, s->tty);
+       do_pam_setcred(1);
+#endif
+
+       /* Fork the child. */
+       if ((pid = fork()) == 0) {
+
+               /* Child.  Reinitialize the log because the pid has changed. */
+               log_init(__progname, options.log_level, options.log_facility, log_stderr);
+               /* Close the master side of the pseudo tty. */
+               close(ptyfd);
+
+               /* Make the pseudo tty our controlling tty. */
+               pty_make_controlling_tty(&ttyfd, s->tty);
+
+               /* Redirect stdin/stdout/stderr from the pseudo tty. */
+               if (dup2(ttyfd, 0) < 0)
+                       error("dup2 stdin: %s", strerror(errno));
+               if (dup2(ttyfd, 1) < 0)
+                       error("dup2 stdout: %s", strerror(errno));
+               if (dup2(ttyfd, 2) < 0)
+                       error("dup2 stderr: %s", strerror(errno));
+
+               /* Close the extra descriptor for the pseudo tty. */
+               close(ttyfd);
+
+               /* record login, etc. similar to login(1) */
+#ifndef HAVE_OSF_SIA
+               if (!(options.use_login && command == NULL))
+                       do_login(s, command);
+# ifdef LOGIN_NEEDS_UTMPX
+               else
+                       do_pre_login(s);
+# endif
+#endif
+
+               /* Do common processing for the child, such as execing the command. */
+               do_child(s, command);
+               /* NOTREACHED */
+       }
+#ifdef HAVE_CYGWIN
+       if (is_winnt)
+               cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+#endif
+       if (pid < 0)
+               packet_disconnect("fork failed: %.100s", strerror(errno));
+       s->pid = pid;
+
+       /* Parent.  Close the slave side of the pseudo tty. */
+       close(ttyfd);
+
+       /*
+        * Create another descriptor of the pty master side for use as the
+        * standard input.  We could use the original descriptor, but this
+        * simplifies code in server_loop.  The descriptor is bidirectional.
+        */
+       fdout = dup(ptyfd);
+       if (fdout < 0)
+               packet_disconnect("dup #1 failed: %.100s", strerror(errno));
+
+       /* we keep a reference to the pty master */
+       ptymaster = dup(ptyfd);
+       if (ptymaster < 0)
+               packet_disconnect("dup #2 failed: %.100s", strerror(errno));
+       s->ptymaster = ptymaster;
+
+       /* Enter interactive session. */
+       packet_set_interactive(1);
+       if (compat20) {
+               session_set_fds(s, ptyfd, fdout, -1);
+       } else {
+               server_loop(pid, ptyfd, fdout, -1);
+               /* server_loop _has_ closed ptyfd and fdout. */
+       }
+}
+
+#ifdef LOGIN_NEEDS_UTMPX
+static void
+do_pre_login(Session *s)
+{
+       socklen_t fromlen;
+       struct sockaddr_storage from;
+       pid_t pid = getpid();
+
+       /*
+        * Get IP address of client. If the connection is not a socket, let
+        * the address be 0.0.0.0.
+        */
+       memset(&from, 0, sizeof(from));
+       if (packet_connection_is_on_socket()) {
+               fromlen = sizeof(from);
+               if (getpeername(packet_get_connection_in(),
+                    (struct sockaddr *) & from, &fromlen) < 0) {
+                       debug("getpeername: %.100s", strerror(errno));
+                       fatal_cleanup();
+               }
+       }
+
+       record_utmp_only(pid, s->tty, s->pw->pw_name,
+           get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
+           (struct sockaddr *)&from);
+}
+#endif
+
+/*
+ * This is called to fork and execute a command.  If another command is
+ * to be forced, execute that instead.
+ */
+void
+do_exec(Session *s, const char *command)
+{
+       if (forced_command) {
+               original_command = command;
+               command = forced_command;
+               debug("Forced command '%.900s'", command);
+       }
+
+       if (s->ttyfd != -1)
+               do_exec_pty(s, command);
+       else
+               do_exec_no_pty(s, command);
+
+       original_command = NULL;
+}
+
+/* administrative, login(1)-like work */
+void
+do_login(Session *s, const char *command)
+{
+       char *time_string;
+       char hostname[MAXHOSTNAMELEN];
+       socklen_t fromlen;
+       struct sockaddr_storage from;
+       time_t last_login_time;
+       struct passwd * pw = s->pw;
+       pid_t pid = getpid();
+
+       /*
+        * Get IP address of client. If the connection is not a socket, let
+        * the address be 0.0.0.0.
+        */
+       memset(&from, 0, sizeof(from));
+       if (packet_connection_is_on_socket()) {
+               fromlen = sizeof(from);
+               if (getpeername(packet_get_connection_in(),
+                    (struct sockaddr *) & from, &fromlen) < 0) {
+                       debug("getpeername: %.100s", strerror(errno));
+                       fatal_cleanup();
+               }
+       }
+
+       /* Get the time and hostname when the user last logged in. */
+       if (options.print_lastlog) {
+               hostname[0] = '\0';
+               last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
+                   hostname, sizeof(hostname));
+       }
+
+       /* Record that there was a login on that tty from the remote host. */
+       record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
+           get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
+           (struct sockaddr *)&from);
+
+#ifdef USE_PAM
+       /*
+        * If password change is needed, do it now.
+        * This needs to occur before the ~/.hushlogin check.
+        */
+       if (is_pam_password_change_required()) {
+               print_pam_messages();
+               do_pam_chauthtok();
+       }
+#endif
+
+       if (check_quietlogin(s, command))
+               return;
+
+#ifdef USE_PAM
+       if (!is_pam_password_change_required())
+               print_pam_messages();
+#endif /* USE_PAM */
+#ifdef WITH_AIXAUTHENTICATE
+       if (aixloginmsg && *aixloginmsg)
+               printf("%s\n", aixloginmsg);
+#endif /* WITH_AIXAUTHENTICATE */
+
+       if (options.print_lastlog && last_login_time != 0) {
+               time_string = ctime(&last_login_time);
+               if (strchr(time_string, '\n'))
+                       *strchr(time_string, '\n') = 0;
+               if (strcmp(hostname, "") == 0)
+                       printf("Last login: %s\r\n", time_string);
+               else
+                       printf("Last login: %s from %s\r\n", time_string, hostname);
+       }
+
+       do_motd();
+}
+
+/*
+ * Display the message of the day.
+ */
+void
+do_motd(void)
+{
+       FILE *f;
+       char buf[256];
+
+       if (options.print_motd) {
+#ifdef HAVE_LOGIN_CAP
+               f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
+                   "/etc/motd"), "r");
+#else
+               f = fopen("/etc/motd", "r");
+#endif
+               if (f) {
+                       while (fgets(buf, sizeof(buf), f))
+                               fputs(buf, stdout);
+                       fclose(f);
+               }
+       }
+}
+
+
+/*
+ * Check for quiet login, either .hushlogin or command given.
+ */
+int
+check_quietlogin(Session *s, const char *command)
+{
+       char buf[256];
+       struct passwd *pw = s->pw;
+       struct stat st;
+
+       /* Return 1 if .hushlogin exists or a command given. */
+       if (command != NULL)
+               return 1;
+       snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
+#ifdef HAVE_LOGIN_CAP
+       if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
+               return 1;
+#else
+       if (stat(buf, &st) >= 0)
+               return 1;
+#endif
+       return 0;
+}
+
+/*
+ * Sets the value of the given variable in the environment.  If the variable
+ * already exists, its value is overriden.
+ */
+static void
+child_set_env(char ***envp, u_int *envsizep, const char *name,
+             const char *value)
+{
+       u_int i, namelen;
+       char **env;
+
+       /*
+        * Find the slot where the value should be stored.  If the variable
+        * already exists, we reuse the slot; otherwise we append a new slot
+        * at the end of the array, expanding if necessary.
+        */
+       env = *envp;
+       namelen = strlen(name);
+       for (i = 0; env[i]; i++)
+               if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
+                       break;
+       if (env[i]) {
+               /* Reuse the slot. */
+               xfree(env[i]);
+       } else {
+               /* New variable.  Expand if necessary. */
+               if (i >= (*envsizep) - 1) {
+                       (*envsizep) += 50;
+                       env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
+               }
+               /* Need to set the NULL pointer at end of array beyond the new slot. */
+               env[i + 1] = NULL;
+       }
+
+       /* Allocate space and format the variable in the appropriate slot. */
+       env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
+       snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
+}
+
+/*
+ * Reads environment variables from the given file and adds/overrides them
+ * into the environment.  If the file does not exist, this does nothing.
+ * Otherwise, it must consist of empty lines, comments (line starts with '#')
+ * and assignments of the form name=value.  No other forms are allowed.
+ */
+static void
+read_environment_file(char ***env, u_int *envsize,
+                     const char *filename)
+{
+       FILE *f;
+       char buf[4096];
+       char *cp, *value;
+
+       f = fopen(filename, "r");
+       if (!f)
+               return;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '#' || *cp == '\n')
+                       continue;
+               if (strchr(cp, '\n'))
+                       *strchr(cp, '\n') = '\0';
+               value = strchr(cp, '=');
+               if (value == NULL) {
+                       fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
+                       continue;
+               }
+               /*
+                * Replace the equals sign by nul, and advance value to
+                * the value string.
+                */
+               *value = '\0';
+               value++;
+               child_set_env(env, envsize, cp, value);
+       }
+       fclose(f);
+}
+
+#ifdef USE_PAM
+/*
+ * Sets any environment variables which have been specified by PAM
+ */
+void do_pam_environment(char ***env, u_int *envsize)
+{
+       char *equals, var_name[512], var_val[512];
+       char **pam_env;
+       int i;
+
+       if ((pam_env = fetch_pam_environment()) == NULL)
+               return;
+
+       for(i = 0; pam_env[i] != NULL; i++) {
+               if ((equals = strstr(pam_env[i], "=")) == NULL)
+                       continue;
+
+               if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) {
+                       memset(var_name, '\0', sizeof(var_name));
+                       memset(var_val, '\0', sizeof(var_val));
+
+                       strncpy(var_name, pam_env[i], equals - pam_env[i]);
+                       strcpy(var_val, equals + 1);
+
+                       debug3("PAM environment: %s=%s", var_name, var_val);
+
+                       child_set_env(env, envsize, var_name, var_val);
+               }
+       }
+}
+#endif /* USE_PAM */
+
+#ifdef HAVE_CYGWIN
+void copy_environment(char ***env, u_int *envsize)
+{
+       char *equals, var_name[512], var_val[512];
+       int i;
+
+       for(i = 0; environ[i] != NULL; i++) {
+               if ((equals = strstr(environ[i], "=")) == NULL)
+                       continue;
+
+               if (strlen(environ[i]) < (sizeof(var_name) - 1)) {
+                       memset(var_name, '\0', sizeof(var_name));
+                       memset(var_val, '\0', sizeof(var_val));
+
+                       strncpy(var_name, environ[i], equals - environ[i]);
+                       strcpy(var_val, equals + 1);
+
+                       debug3("Copy environment: %s=%s", var_name, var_val);
+
+                       child_set_env(env, envsize, var_name, var_val);
+               }
+       }
+}
+#endif
+
+#if defined(HAVE_GETUSERATTR)
+/*
+ * AIX-specific login initialisation
+ */
+void set_limit(char *user, char *soft, char *hard, int resource, int mult)
+{
+       struct rlimit rlim;
+       int slim, hlim;
+
+       getrlimit(resource, &rlim);
+
+       slim = 0;
+       if (getuserattr(user, soft, &slim, SEC_INT) != -1) {
+               if (slim < 0) {
+                       rlim.rlim_cur = RLIM_INFINITY;
+               } else if (slim != 0) {
+                       /* See the wackiness below */
+                       if (rlim.rlim_cur == slim * mult)
+                               slim = 0;
+                       else
+                               rlim.rlim_cur = slim * mult;
+               }
+       }
+
+       hlim = 0;
+       if (getuserattr(user, hard, &hlim, SEC_INT) != -1) {
+               if (hlim < 0) {
+                       rlim.rlim_max = RLIM_INFINITY;
+               } else if (hlim != 0) {
+                       rlim.rlim_max = hlim * mult;
+               }
+       }
+
+       /*
+        * XXX For cpu and fsize the soft limit is set to the hard limit
+        * if the hard limit is left at its default value and the soft limit
+        * is changed from its default value, either by requesting it
+        * (slim == 0) or by setting it to the current default.  At least
+        * that's how rlogind does it.  If you're confused you're not alone.
+        * Bug or feature? AIX 4.3.1.2
+        */
+       if ((!strcmp(soft, "fsize") || !strcmp(soft, "cpu"))
+           && hlim == 0 && slim != 0)
+               rlim.rlim_max = rlim.rlim_cur;
+       /* A specified hard limit limits the soft limit */
+       else if (hlim > 0 && rlim.rlim_cur > rlim.rlim_max)
+               rlim.rlim_cur = rlim.rlim_max;
+       /* A soft limit can increase a hard limit */
+       else if (rlim.rlim_cur > rlim.rlim_max)
+               rlim.rlim_max = rlim.rlim_cur;
+
+       if (setrlimit(resource, &rlim) != 0)
+               error("setrlimit(%.10s) failed: %.100s", soft, strerror(errno));
+}
+
+void set_limits_from_userattr(char *user)
+{
+       int mask;
+       char buf[16];
+
+       set_limit(user, S_UFSIZE, S_UFSIZE_HARD, RLIMIT_FSIZE, 512);
+       set_limit(user, S_UCPU, S_UCPU_HARD, RLIMIT_CPU, 1);
+       set_limit(user, S_UDATA, S_UDATA_HARD, RLIMIT_DATA, 512);
+       set_limit(user, S_USTACK, S_USTACK_HARD, RLIMIT_STACK, 512);
+       set_limit(user, S_URSS, S_URSS_HARD, RLIMIT_RSS, 512);
+       set_limit(user, S_UCORE, S_UCORE_HARD, RLIMIT_CORE, 512);
+#if defined(S_UNOFILE)
+       set_limit(user, S_UNOFILE, S_UNOFILE_HARD, RLIMIT_NOFILE, 1);
+#endif
+
+       if (getuserattr(user, S_UMASK, &mask, SEC_INT) != -1) {
+               /* Convert decimal to octal */
+               (void) snprintf(buf, sizeof(buf), "%d", mask);
+               if (sscanf(buf, "%o", &mask) == 1)
+                       umask(mask);
+       }
+}
+#endif /* defined(HAVE_GETUSERATTR) */
+
+/*
+ * Performs common processing for the child, such as setting up the
+ * environment, closing extra file descriptors, setting the user and group
+ * ids, and executing the command or shell.
+ */
+void
+do_child(Session *s, const char *command)
+{
+       const char *shell, *hostname = NULL, *cp = NULL;
+       struct passwd *pw = s->pw;
+       char buf[256];
+       char cmd[1024];
+       FILE *f = NULL;
+       u_int envsize, i;
+       char **env;
+       extern char **environ;
+       struct stat st;
+       char *argv[10];
+       int do_xauth;
+#ifdef WITH_IRIX_PROJECT
+       prid_t projid;
+#endif /* WITH_IRIX_PROJECT */
+#ifdef WITH_IRIX_JOBS
+       jid_t jid = 0;
+#else
+#ifdef WITH_IRIX_ARRAY
+       int jid = 0;
+#endif /* WITH_IRIX_ARRAY */
+#endif /* WITH_IRIX_JOBS */
+
+       do_xauth =
+           s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
+
+       /* remove hostkey from the child's memory */
+       destroy_sensitive_data();
+
+       /* login(1) is only called if we execute the login shell */
+       if (options.use_login && command != NULL)
+               options.use_login = 0;
+
+#if !defined(HAVE_OSF_SIA)
+       if (!options.use_login) {
+# ifdef HAVE_LOGIN_CAP
+               if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+                       f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
+                           _PATH_NOLOGIN), "r");
+# else /* HAVE_LOGIN_CAP */
+               if (pw->pw_uid)
+                       f = fopen(_PATH_NOLOGIN, "r");
+# endif /* HAVE_LOGIN_CAP */
+               if (f) {
+                       /* /etc/nologin exists.  Print its contents and exit. */
+                       while (fgets(buf, sizeof(buf), f))
+                               fputs(buf, stderr);
+                       fclose(f);
+                       exit(254);
+               }
+       }
+#endif /* HAVE_OSF_SIA */
+
+       /* Set login name, uid, gid, and groups. */
+       /* Login(1) does this as well, and it needs uid 0 for the "-h"
+          switch, so we let login(1) to this for us. */
+       if (!options.use_login) {
+#ifdef HAVE_OSF_SIA
+               session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty);
+               if (!check_quietlogin(s, command))
+                       do_motd();
+#else /* HAVE_OSF_SIA */
+#ifdef HAVE_CYGWIN
+               if (is_winnt) {
+#else
+               if (getuid() == 0 || geteuid() == 0) {
+#endif
+# ifdef HAVE_GETUSERATTR
+                       set_limits_from_userattr(pw->pw_name);
+# endif /* HAVE_GETUSERATTR */
+# ifdef HAVE_LOGIN_CAP
+                       if (setusercontext(lc, pw, pw->pw_uid,
+                           (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
+                               perror("unable to set user context");
+                               exit(1);
+                       }
+# else /* HAVE_LOGIN_CAP */
+#if defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
+                       /* Sets login uid for accounting */
+                       if (getluid() == -1 && setluid(pw->pw_uid) == -1)
+                               error("setluid: %s", strerror(errno));
+#endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */
+
+                       if (setlogin(pw->pw_name) < 0)
+                               error("setlogin failed: %s", strerror(errno));
+                       if (setgid(pw->pw_gid) < 0) {
+                               perror("setgid");
+                               exit(1);
+                       }
+                       /* Initialize the group list. */
+                       if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+                               perror("initgroups");
+                               exit(1);
+                       }
+                       endgrent();
+#  ifdef USE_PAM
+                       /*
+                        * PAM credentials may take the form of 
+                        * supplementary groups. These will have been 
+                        * wiped by the above initgroups() call.
+                        * Reestablish them here.
+                        */
+                       do_pam_setcred(0);
+#  endif /* USE_PAM */
+#  ifdef WITH_IRIX_JOBS
+                       jid = jlimit_startjob(pw->pw_name, pw->pw_uid, "interactive");
+                       if (jid == -1) {
+                               fatal("Failed to create job container: %.100s",
+                                     strerror(errno));
+                       }
+#  endif /* WITH_IRIX_JOBS */
+#  ifdef WITH_IRIX_ARRAY
+                       /* initialize array session */
+                       if (jid == 0) {
+                               if (newarraysess() != 0)
+                                       fatal("Failed to set up new array session: %.100s",
+                                             strerror(errno));
+                       }
+#  endif /* WITH_IRIX_ARRAY */
+#  ifdef WITH_IRIX_PROJECT
+                       /* initialize irix project info */
+                       if ((projid = getdfltprojuser(pw->pw_name)) == -1) {
+                         debug("Failed to get project id, using projid 0");
+                         projid = 0;
+                       }
+                       if (setprid(projid))
+                         fatal("Failed to initialize project %d for %s: %.100s",
+                               (int)projid, pw->pw_name, strerror(errno));
+#  endif /* WITH_IRIX_PROJECT */
+#ifdef WITH_IRIX_AUDIT
+                       if (sysconf(_SC_AUDIT)) {
+                               debug("Setting sat id to %d", (int) pw->pw_uid);
+                               if (satsetid(pw->pw_uid))
+                                       debug("error setting satid: %.100s", strerror(errno));
+                       }
+#endif /* WITH_IRIX_AUDIT */
+
+#ifdef _AIX
+                       /*
+                        * AIX has a "usrinfo" area where logname and
+                        * other stuff is stored - a few applications
+                        * actually use this and die if it's not set
+                        */
+                       if (s->ttyfd == -1)
+                               s->tty[0] = '\0';
+                       cp = xmalloc(22 + strlen(s->tty) + 
+                           2 * strlen(pw->pw_name));
+                       i = sprintf(cp, "LOGNAME=%s%cNAME=%s%cTTY=%s%c%c",
+                           pw->pw_name, 0, pw->pw_name, 0, s->tty, 0, 0);
+                       if (usrinfo(SETUINFO, cp, i) == -1)
+                               fatal("Couldn't set usrinfo: %s", 
+                                   strerror(errno));
+                       debug3("AIX/UsrInfo: set len %d", i);
+                       xfree(cp);
+#endif
+
+                       /* Permanently switch to the desired uid. */
+                       permanently_set_uid(pw);
+# endif /* HAVE_LOGIN_CAP */
+               }
+#endif /* HAVE_OSF_SIA */
+
+#ifdef HAVE_CYGWIN
+               if (is_winnt)
+#endif
+               if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+                       fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
+       }
+       /*
+        * Get the shell from the password data.  An empty shell field is
+        * legal, and means /bin/sh.
+        */
+       shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
+#ifdef HAVE_LOGIN_CAP
+       shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
+#endif
+
+       /* Initialize the environment. */
+       envsize = 100;
+       env = xmalloc(envsize * sizeof(char *));
+       env[0] = NULL;
+
+#ifdef HAVE_CYGWIN
+       /*
+        * The Windows environment contains some setting which are
+        * important for a running system. They must not be dropped.
+        */
+       copy_environment(&env, &envsize);
+#endif
+
+       if (!options.use_login) {
+               /* Set basic environment. */
+               child_set_env(&env, &envsize, "USER", pw->pw_name);
+               child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
+               child_set_env(&env, &envsize, "HOME", pw->pw_dir);
+#ifdef HAVE_LOGIN_CAP
+               (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH);
+               child_set_env(&env, &envsize, "PATH", getenv("PATH"));
+#else /* HAVE_LOGIN_CAP */
+# ifndef HAVE_CYGWIN
+               /*
+                * There's no standard path on Windows. The path contains
+                * important components pointing to the system directories,
+                * needed for loading shared libraries. So the path better
+                * remains intact here.
+                */
+               child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
+# endif /* HAVE_CYGWIN */
+#endif /* HAVE_LOGIN_CAP */
+
+               snprintf(buf, sizeof buf, "%.200s/%.50s",
+                        _PATH_MAILDIR, pw->pw_name);
+               child_set_env(&env, &envsize, "MAIL", buf);
+
+               /* Normal systems set SHELL by default. */
+               child_set_env(&env, &envsize, "SHELL", shell);
+       }
+       if (getenv("TZ"))
+               child_set_env(&env, &envsize, "TZ", getenv("TZ"));
+
+       /* Set custom environment options from RSA authentication. */
+       if (!options.use_login) {
+               while (custom_environment) {
+                       struct envstring *ce = custom_environment;
+                       char *s = ce->s;
+                       int i;
+                       for (i = 0; s[i] != '=' && s[i]; i++)
+                               ;
+                       if (s[i] == '=') {
+                               s[i] = 0;
+                               child_set_env(&env, &envsize, s, s + i + 1);
+                       }
+                       custom_environment = ce->next;
+                       xfree(ce->s);
+                       xfree(ce);
+               }
+       }
+
+       snprintf(buf, sizeof buf, "%.50s %d %d",
+                get_remote_ipaddr(), get_remote_port(), get_local_port());
+       child_set_env(&env, &envsize, "SSH_CLIENT", buf);
+
+       if (s->ttyfd != -1)
+               child_set_env(&env, &envsize, "SSH_TTY", s->tty);
+       if (s->term)
+               child_set_env(&env, &envsize, "TERM", s->term);
+       if (s->display)
+               child_set_env(&env, &envsize, "DISPLAY", s->display);
+       if (original_command)
+               child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
+                   original_command);
+
+#ifdef _AIX
+       if ((cp = getenv("AUTHSTATE")) != NULL)
+               child_set_env(&env, &envsize, "AUTHSTATE", cp);
+       if ((cp = getenv("KRB5CCNAME")) != NULL)
+               child_set_env(&env, &envsize, "KRB5CCNAME", cp);
+       read_environment_file(&env, &envsize, "/etc/environment");
+#endif
+#ifdef KRB4
+       if (s->authctxt->krb4_ticket_file)
+               child_set_env(&env, &envsize, "KRBTKFILE",
+                   s->authctxt->krb4_ticket_file);
+#endif
+#ifdef KRB5
+       if (s->authctxt->krb5_ticket_file)
+               child_set_env(&env, &envsize, "KRB5CCNAME",
+                   s->authctxt->krb5_ticket_file);
+#endif
+#ifdef USE_PAM
+       /* Pull in any environment variables that may have been set by PAM. */
+       do_pam_environment(&env, &envsize);
+#endif /* USE_PAM */
+
+       if (auth_get_socket_name() != NULL)
+               child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
+                             auth_get_socket_name());
+
+       /* read $HOME/.ssh/environment. */
+       if (!options.use_login) {
+               snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
+                   pw->pw_dir);
+               read_environment_file(&env, &envsize, buf);
+       }
+       if (debug_flag) {
+               /* dump the environment */
+               fprintf(stderr, "Environment:\n");
+               for (i = 0; env[i]; i++)
+                       fprintf(stderr, "  %.200s\n", env[i]);
+       }
+       /* we have to stash the hostname before we close our socket. */
+       if (options.use_login)
+               hostname = get_remote_name_or_ip(utmp_len,
+                   options.reverse_mapping_check);
+       /*
+        * Close the connection descriptors; note that this is the child, and
+        * the server will still have the socket open, and it is important
+        * that we do not shutdown it.  Note that the descriptors cannot be
+        * closed before building the environment, as we call
+        * get_remote_ipaddr there.
+        */
+       if (packet_get_connection_in() == packet_get_connection_out())
+               close(packet_get_connection_in());
+       else {
+               close(packet_get_connection_in());
+               close(packet_get_connection_out());
+       }
+       /*
+        * Close all descriptors related to channels.  They will still remain
+        * open in the parent.
+        */
+       /* XXX better use close-on-exec? -markus */
+       channel_close_all();
+
+       /*
+        * Close any extra file descriptors.  Note that there may still be
+        * descriptors left by system functions.  They will be closed later.
+        */
+       endpwent();
+
+       /*
+        * Close any extra open file descriptors so that we don\'t have them
+        * hanging around in clients.  Note that we want to do this after
+        * initgroups, because at least on Solaris 2.3 it leaves file
+        * descriptors open.
+        */
+       for (i = 3; i < 64; i++)
+               close(i);
+
+       /*
+        * Must take new environment into use so that .ssh/rc, /etc/sshrc and
+        * xauth are run in the proper environment.
+        */
+       environ = env;
+
+#ifdef AFS
+       /* Try to get AFS tokens for the local cell. */
+       if (k_hasafs()) {
+               char cell[64];
+               
+               if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
+                       krb_afslog(cell, 0);
+               
+               krb_afslog(0, 0);
+       }
+#endif /* AFS */
+
+       /* Change current directory to the user\'s home directory. */
+       if (chdir(pw->pw_dir) < 0) {
+               fprintf(stderr, "Could not chdir to home directory %s: %s\n",
+                   pw->pw_dir, strerror(errno));
+#ifdef HAVE_LOGIN_CAP
+               if (login_getcapbool(lc, "requirehome", 0))
+                       exit(1);
+#endif
+       }
+
+       /*
+        * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
+        * in this order).
+        */
+       if (!options.use_login) {
+               /* ignore _PATH_SSH_USER_RC for subsystems */
+               if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
+                       snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
+                           shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
+                       if (debug_flag)
+                               fprintf(stderr, "Running %s\n", cmd);
+                       f = popen(cmd, "w");
+                       if (f) {
+                               if (do_xauth)
+                                       fprintf(f, "%s %s\n", s->auth_proto,
+                                           s->auth_data);
+                               pclose(f);
+                       } else
+                               fprintf(stderr, "Could not run %s\n",
+                                   _PATH_SSH_USER_RC);
+               } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
+                       if (debug_flag)
+                               fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
+                                   _PATH_SSH_SYSTEM_RC);
+                       f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
+                       if (f) {
+                               if (do_xauth)
+                                       fprintf(f, "%s %s\n", s->auth_proto,
+                                           s->auth_data);
+                               pclose(f);
+                       } else
+                               fprintf(stderr, "Could not run %s\n",
+                                   _PATH_SSH_SYSTEM_RC);
+               } else if (do_xauth && options.xauth_location != NULL) {
+                       /* Add authority data to .Xauthority if appropriate. */
+                       char *screen = strchr(s->display, ':');
+
+                       if (debug_flag) {
+                               fprintf(stderr,
+                                   "Running %.100s add "
+                                   "%.100s %.100s %.100s\n",
+                                   options.xauth_location, s->display,
+                                   s->auth_proto, s->auth_data);
+                               if (screen != NULL)
+                                       fprintf(stderr,
+                                           "Adding %.*s/unix%s %s %s\n",
+                                           (int)(screen - s->display),
+                                           s->display, screen,
+                                           s->auth_proto, s->auth_data);
+                       }
+                       snprintf(cmd, sizeof cmd, "%s -q -",
+                           options.xauth_location);
+                       f = popen(cmd, "w");
+                       if (f) {
+                               fprintf(f, "add %s %s %s\n", s->display,
+                                   s->auth_proto, s->auth_data);
+                               if (screen != NULL)
+                                       fprintf(f, "add %.*s/unix%s %s %s\n",
+                                           (int)(screen - s->display),
+                                           s->display, screen,
+                                           s->auth_proto,
+                                           s->auth_data);
+                               pclose(f);
+                       } else {
+                               fprintf(stderr, "Could not run %s\n",
+                                   cmd);
+                       }
+               }
+               /* Get the last component of the shell name. */
+               cp = strrchr(shell, '/');
+               if (cp)
+                       cp++;
+               else
+                       cp = shell;
+       }
+
+       /* restore SIGPIPE for child */
+       signal(SIGPIPE,  SIG_DFL);
+
+       /*
+        * If we have no command, execute the shell.  In this case, the shell
+        * name to be passed in argv[0] is preceded by '-' to indicate that
+        * this is a login shell.
+        */
+       if (!command) {
+               if (!options.use_login) {
+                       char buf[256];
+
+                       /* Start the shell.  Set initial character to '-'. */
+                       buf[0] = '-';
+                       strncpy(buf + 1, cp, sizeof(buf) - 1);
+                       buf[sizeof(buf) - 1] = 0;
+
+                       /* Execute the shell. */
+                       argv[0] = buf;
+                       argv[1] = NULL;
+                       execve(shell, argv, env);
+
+                       /* Executing the shell failed. */
+                       perror(shell);
+                       exit(1);
+
+               } else {
+                       /* Launch login(1). */
+
+                       execl(LOGIN_PROGRAM, "login", "-h", hostname,
+#ifdef LOGIN_NEEDS_TERM
+                            s->term? s->term : "unknown",
+#endif
+                            "-p", "-f", "--", pw->pw_name, (char *)NULL);
+
+                       /* Login couldn't be executed, die. */
+
+                       perror("login");
+                       exit(1);
+               }
+       }
+       /*
+        * Execute the command using the user's shell.  This uses the -c
+        * option to execute the command.
+        */
+       argv[0] = (char *) cp;
+       argv[1] = "-c";
+       argv[2] = (char *) command;
+       argv[3] = NULL;
+       execve(shell, argv, env);
+       perror(shell);
+       exit(1);
+}
+
+Session *
+session_new(void)
+{
+       int i;
+       static int did_init = 0;
+       if (!did_init) {
+               debug("session_new: init");
+               for(i = 0; i < MAX_SESSIONS; i++) {
+                       sessions[i].used = 0;
+               }
+               did_init = 1;
+       }
+       for(i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               if (! s->used) {
+                       memset(s, 0, sizeof(*s));
+                       s->chanid = -1;
+                       s->ptyfd = -1;
+                       s->ttyfd = -1;
+                       s->used = 1;
+                       s->self = i;
+                       debug("session_new: session %d", i);
+                       return s;
+               }
+       }
+       return NULL;
+}
+
+static void
+session_dump(void)
+{
+       int i;
+       for(i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               debug("dump: used %d session %d %p channel %d pid %d",
+                   s->used,
+                   s->self,
+                   s,
+                   s->chanid,
+                   s->pid);
+       }
+}
+
+int
+session_open(Authctxt *authctxt, int chanid)
+{
+       Session *s = session_new();
+       debug("session_open: channel %d", chanid);
+       if (s == NULL) {
+               error("no more sessions");
+               return 0;
+       }
+       s->authctxt = authctxt;
+       s->pw = authctxt->pw;
+       if (s->pw == NULL)
+               fatal("no user for session %d", s->self);
+       debug("session_open: session %d: link with channel %d", s->self, chanid);
+       s->chanid = chanid;
+       return 1;
+}
+
+static Session *
+session_by_channel(int id)
+{
+       int i;
+       for(i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->chanid == id) {
+                       debug("session_by_channel: session %d channel %d", i, id);
+                       return s;
+               }
+       }
+       debug("session_by_channel: unknown channel %d", id);
+       session_dump();
+       return NULL;
+}
+
+static Session *
+session_by_pid(pid_t pid)
+{
+       int i;
+       debug("session_by_pid: pid %d", pid);
+       for(i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->pid == pid)
+                       return s;
+       }
+       error("session_by_pid: unknown pid %d", pid);
+       session_dump();
+       return NULL;
+}
+
+static int
+session_window_change_req(Session *s)
+{
+       s->col = packet_get_int();
+       s->row = packet_get_int();
+       s->xpixel = packet_get_int();
+       s->ypixel = packet_get_int();
+       packet_done();
+       pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
+       return 1;
+}
+
+static int
+session_pty_req(Session *s)
+{
+       u_int len;
+       int n_bytes;
+
+       if (no_pty_flag) {
+               debug("Allocating a pty not permitted for this authentication.");
+               return 0;
+       }
+       if (s->ttyfd != -1) {
+               packet_disconnect("Protocol error: you already have a pty.");
+               return 0;
+       }
+
+       s->term = packet_get_string(&len);
+
+       if (compat20) {
+               s->col = packet_get_int();
+               s->row = packet_get_int();
+       } else {
+               s->row = packet_get_int();
+               s->col = packet_get_int();
+       }
+       s->xpixel = packet_get_int();
+       s->ypixel = packet_get_int();
+
+       if (strcmp(s->term, "") == 0) {
+               xfree(s->term);
+               s->term = NULL;
+       }
+
+       /* Allocate a pty and open it. */
+       debug("Allocating pty.");
+       if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
+               if (s->term)
+                       xfree(s->term);
+               s->term = NULL;
+               s->ptyfd = -1;
+               s->ttyfd = -1;
+               error("session_pty_req: session %d alloc failed", s->self);
+               return 0;
+       }
+       debug("session_pty_req: session %d alloc %s", s->self, s->tty);
+
+       /* for SSH1 the tty modes length is not given */
+       if (!compat20)
+               n_bytes = packet_remaining();
+       tty_parse_modes(s->ttyfd, &n_bytes);
+
+       /*
+        * Add a cleanup function to clear the utmp entry and record logout
+        * time in case we call fatal() (e.g., the connection gets closed).
+        */
+       fatal_add_cleanup(session_pty_cleanup, (void *)s);
+       pty_setowner(s->pw, s->tty);
+
+       /* Set window size from the packet. */
+       pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
+
+       packet_done();
+       session_proctitle(s);
+       return 1;
+}
+
+static int
+session_subsystem_req(Session *s)
+{
+       struct stat st;
+       u_int len;
+       int success = 0;
+       char *cmd, *subsys = packet_get_string(&len);
+       int i;
+
+       packet_done();
+       log("subsystem request for %s", subsys);
+
+       for (i = 0; i < options.num_subsystems; i++) {
+               if (strcmp(subsys, options.subsystem_name[i]) == 0) {
+                       cmd = options.subsystem_command[i];
+                       if (stat(cmd, &st) < 0) {
+                               error("subsystem: cannot stat %s: %s", cmd,
+                                   strerror(errno));
+                               break;
+                       }
+                       debug("subsystem: exec() %s", cmd);
+                       s->is_subsystem = 1;
+                       do_exec(s, cmd);
+                       success = 1;
+               }
+       }
+
+       if (!success)
+               log("subsystem request for %s failed, subsystem not found",
+                   subsys);
+
+       xfree(subsys);
+       return success;
+}
+
+static int
+session_x11_req(Session *s)
+{
+       int success;
+
+       s->single_connection = packet_get_char();
+       s->auth_proto = packet_get_string(NULL);
+       s->auth_data = packet_get_string(NULL);
+       s->screen = packet_get_int();
+       packet_done();
+
+       success = session_setup_x11fwd(s);
+       if (!success) {
+               xfree(s->auth_proto);
+               xfree(s->auth_data);
+               s->auth_proto = NULL;
+               s->auth_data = NULL;
+       }
+       return success;
+}
+
+static int
+session_shell_req(Session *s)
+{
+       packet_done();
+       do_exec(s, NULL);
+       return 1;
+}
+
+static int
+session_exec_req(Session *s)
+{
+       u_int len;
+       char *command = packet_get_string(&len);
+       packet_done();
+       do_exec(s, command);
+       xfree(command);
+       return 1;
+}
+
+static int
+session_auth_agent_req(Session *s)
+{
+       static int called = 0;
+       packet_done();
+       if (no_agent_forwarding_flag) {
+               debug("session_auth_agent_req: no_agent_forwarding_flag");
+               return 0;
+       }
+       if (called) {
+               return 0;
+       } else {
+               called = 1;
+               return auth_input_request_forwarding(s->pw);
+       }
+}
+
+void
+session_input_channel_req(int id, void *arg)
+{
+       u_int len;
+       int reply;
+       int success = 0;
+       char *rtype;
+       Session *s;
+       Channel *c;
+
+       rtype = packet_get_string(&len);
+       reply = packet_get_char();
+
+       s = session_by_channel(id);
+       if (s == NULL)
+               fatal("session_input_channel_req: channel %d: no session", id);
+       c = channel_lookup(id);
+       if (c == NULL)
+               fatal("session_input_channel_req: channel %d: bad channel", id);
+
+       debug("session_input_channel_req: session %d channel %d request %s reply %d",
+           s->self, id, rtype, reply);
+
+       /*
+        * a session is in LARVAL state until a shell, a command
+        * or a subsystem is executed
+        */
+       if (c->type == SSH_CHANNEL_LARVAL) {
+               if (strcmp(rtype, "shell") == 0) {
+                       success = session_shell_req(s);
+               } else if (strcmp(rtype, "exec") == 0) {
+                       success = session_exec_req(s);
+               } else if (strcmp(rtype, "pty-req") == 0) {
+                       success =  session_pty_req(s);
+               } else if (strcmp(rtype, "x11-req") == 0) {
+                       success = session_x11_req(s);
+               } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
+                       success = session_auth_agent_req(s);
+               } else if (strcmp(rtype, "subsystem") == 0) {
+                       success = session_subsystem_req(s);
+               }
+       }
+       if (strcmp(rtype, "window-change") == 0) {
+               success = session_window_change_req(s);
+       }
+
+       if (reply) {
+               packet_start(success ?
+                   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+               packet_put_int(c->remote_id);
+               packet_send();
+       }
+       xfree(rtype);
+}
+
+void
+session_set_fds(Session *s, int fdin, int fdout, int fderr)
+{
+       if (!compat20)
+               fatal("session_set_fds: called for proto != 2.0");
+       /*
+        * now that have a child and a pipe to the child,
+        * we can activate our channel and register the fd's
+        */
+       if (s->chanid == -1)
+               fatal("no channel for session %d", s->self);
+       channel_set_fds(s->chanid,
+           fdout, fdin, fderr,
+           fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
+           1);
+}
+
+/*
+ * Function to perform pty cleanup. Also called if we get aborted abnormally
+ * (e.g., due to a dropped connection).
+ */
+static void
+session_pty_cleanup(void *session)
+{
+       Session *s = session;
+
+       if (s == NULL) {
+               error("session_pty_cleanup: no session");
+               return;
+       }
+       if (s->ttyfd == -1)
+               return;
+
+       debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
+
+       /* Record that the user has logged out. */
+       if (s->pid != 0)
+               record_logout(s->pid, s->tty);
+
+       /* Release the pseudo-tty. */
+       pty_release(s->tty);
+
+       /*
+        * Close the server side of the socket pairs.  We must do this after
+        * the pty cleanup, so that another process doesn't get this pty
+        * while we're still cleaning up.
+        */
+       if (close(s->ptymaster) < 0)
+               error("close(s->ptymaster): %s", strerror(errno));
+
+       /* unlink pty from session */
+       s->ttyfd = -1;
+}
+
+static void
+session_exit_message(Session *s, int status)
+{
+       Channel *c;
+       if (s == NULL)
+               fatal("session_close: no session");
+       c = channel_lookup(s->chanid);
+       if (c == NULL)
+               fatal("session_exit_message: session %d: no channel %d",
+                   s->self, s->chanid);
+       debug("session_exit_message: session %d channel %d pid %d",
+           s->self, s->chanid, s->pid);
+
+       if (WIFEXITED(status)) {
+               channel_request_start(s->chanid,
+                   "exit-status", 0);
+               packet_put_int(WEXITSTATUS(status));
+               packet_send();
+       } else if (WIFSIGNALED(status)) {
+               channel_request_start(s->chanid,
+                   "exit-signal", 0);
+               packet_put_int(WTERMSIG(status));
+#ifdef WCOREDUMP
+               packet_put_char(WCOREDUMP(status));
+#else /* WCOREDUMP */
+               packet_put_char(0);
+#endif /* WCOREDUMP */
+               packet_put_cstring("");
+               packet_put_cstring("");
+               packet_send();
+       } else {
+               /* Some weird exit cause.  Just exit. */
+               packet_disconnect("wait returned status %04x.", status);
+       }
+
+       /* disconnect channel */
+       debug("session_exit_message: release channel %d", s->chanid);
+       channel_cancel_cleanup(s->chanid);
+       /*
+        * emulate a write failure with 'chan_write_failed', nobody will be
+        * interested in data we write.
+        * Note that we must not call 'chan_read_failed', since there could
+        * be some more data waiting in the pipe.
+        */
+       if (c->ostate != CHAN_OUTPUT_CLOSED)
+               chan_write_failed(c);
+       s->chanid = -1;
+}
+
+static void
+session_close(Session *s)
+{
+       debug("session_close: session %d pid %d", s->self, s->pid);
+       if (s->ttyfd != -1) {
+               fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+               session_pty_cleanup(s);
+       }
+       if (s->term)
+               xfree(s->term);
+       if (s->display)
+               xfree(s->display);
+       if (s->auth_data)
+               xfree(s->auth_data);
+       if (s->auth_proto)
+               xfree(s->auth_proto);
+       s->used = 0;
+       session_proctitle(s);
+}
+
+void
+session_close_by_pid(pid_t pid, int status)
+{
+       Session *s = session_by_pid(pid);
+       if (s == NULL) {
+               debug("session_close_by_pid: no session for pid %d", pid);
+               return;
+       }
+       if (s->chanid != -1)
+               session_exit_message(s, status);
+       session_close(s);
+}
+
+/*
+ * this is called when a channel dies before
+ * the session 'child' itself dies
+ */
+void
+session_close_by_channel(int id, void *arg)
+{
+       Session *s = session_by_channel(id);
+       if (s == NULL) {
+               debug("session_close_by_channel: no session for id %d", id);
+               return;
+       }
+       debug("session_close_by_channel: channel %d child %d", id, s->pid);
+       if (s->pid != 0) {
+               debug("session_close_by_channel: channel %d: has child", id);
+               /*
+                * delay detach of session, but release pty, since
+                * the fd's to the child are already closed
+                */
+               if (s->ttyfd != -1) {
+                       fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+                       session_pty_cleanup(s);
+               }
+               return;
+       }
+       /* detach by removing callback */
+       channel_cancel_cleanup(s->chanid);
+       s->chanid = -1;
+       session_close(s);
+}
+
+void
+session_destroy_all(void)
+{
+       int i;
+       for(i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               if (s->used) 
+                       session_close(s);
+       }
+}
+
+static char *
+session_tty_list(void)
+{
+       static char buf[1024];
+       int i;
+       buf[0] = '\0';
+       for(i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->ttyfd != -1) {
+                       if (buf[0] != '\0')
+                               strlcat(buf, ",", sizeof buf);
+                       strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf);
+               }
+       }
+       if (buf[0] == '\0')
+               strlcpy(buf, "notty", sizeof buf);
+       return buf;
+}
+
+void
+session_proctitle(Session *s)
+{
+       if (s->pw == NULL)
+               error("no user for session %d", s->self);
+       else
+               setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
+}
+
+int
+session_setup_x11fwd(Session *s)
+{
+       struct stat st;
+
+       if (no_x11_forwarding_flag) {
+               packet_send_debug("X11 forwarding disabled in user configuration file.");
+               return 0;
+       }
+       if (!options.x11_forwarding) {
+               debug("X11 forwarding disabled in server configuration file.");
+               return 0;
+       }
+       if (!options.xauth_location ||
+           (stat(options.xauth_location, &st) == -1)) {
+               packet_send_debug("No xauth program; cannot forward with spoofing.");
+               return 0;
+       }
+       if (options.use_login) {
+               packet_send_debug("X11 forwarding disabled; "
+                   "not compatible with UseLogin=yes.");
+               return 0;
+       }
+       if (s->display != NULL) {
+               debug("X11 display already set.");
+               return 0;
+       }
+       s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
+       if (s->display == NULL) {
+               debug("x11_create_display_inet failed.");
+               return 0;
+       }
+       return 1;
+}
+
+static void
+do_authenticated2(Authctxt *authctxt)
+{
+       server_loop2(authctxt);
+}
diff --git a/openssh/session.h b/openssh/session.h
new file mode 100644 (file)
index 0000000..6d5b8e6
--- /dev/null
@@ -0,0 +1,37 @@
+/*     $OpenBSD: session.h,v 1.13 2001/10/10 22:18:47 markus Exp $     */
+
+/*
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SESSION_H
+#define SESSION_H
+
+void    do_authenticated(Authctxt *);
+
+int     session_open(Authctxt*, int);
+void    session_input_channel_req(int, void *);
+void    session_close_by_pid(pid_t, int);
+void    session_close_by_channel(int, void *);
+void    session_destroy_all(void);
+
+#endif
diff --git a/openssh/sftp-client.c b/openssh/sftp-client.c
new file mode 100644 (file)
index 0000000..4f2a1e2
--- /dev/null
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* XXX: memleaks */
+/* XXX: signed vs unsigned */
+/* XXX: redesign to allow concurrent overlapped operations */
+/* XXX: we use fatal too much, error may be more appropriate in places */
+/* XXX: copy between two remote sites */
+
+#include "includes.h"
+RCSID("$OpenBSD: sftp-client.c,v 1.18 2001/07/14 15:10:16 stevesk Exp $");
+
+#include "buffer.h"
+#include "bufaux.h"
+#include "getput.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "atomicio.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+#include "sftp-client.h"
+
+/* How much data to read/write at at time during copies */
+/* XXX: what should this be? */
+#define COPY_SIZE      8192
+
+/* Message ID */
+static u_int msg_id = 1;
+
+static void
+send_msg(int fd, Buffer *m)
+{
+       int mlen = buffer_len(m);
+       int len;
+       Buffer oqueue;
+
+       buffer_init(&oqueue);
+       buffer_put_int(&oqueue, mlen);
+       buffer_append(&oqueue, buffer_ptr(m), mlen);
+       buffer_consume(m, mlen);
+
+       len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
+       if (len <= 0)
+               fatal("Couldn't send packet: %s", strerror(errno));
+
+       buffer_free(&oqueue);
+}
+
+static void
+get_msg(int fd, Buffer *m)
+{
+       u_int len, msg_len;
+       unsigned char buf[4096];
+
+       len = atomicio(read, fd, buf, 4);
+       if (len == 0)
+               fatal("Connection closed");
+       else if (len == -1)
+               fatal("Couldn't read packet: %s", strerror(errno));
+
+       msg_len = GET_32BIT(buf);
+       if (msg_len > 256 * 1024)
+               fatal("Received message too long %d", msg_len);
+
+       while (msg_len) {
+               len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
+               if (len == 0)
+                       fatal("Connection closed");
+               else if (len == -1)
+                       fatal("Couldn't read packet: %s", strerror(errno));
+
+               msg_len -= len;
+               buffer_append(m, buf, len);
+       }
+}
+
+static void
+send_string_request(int fd, u_int id, u_int code, char *s,
+    u_int len)
+{
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, code);
+       buffer_put_int(&msg, id);
+       buffer_put_string(&msg, s, len);
+       send_msg(fd, &msg);
+       debug3("Sent message fd %d T:%d I:%d", fd, code, id);
+       buffer_free(&msg);
+}
+
+static void
+send_string_attrs_request(int fd, u_int id, u_int code, char *s,
+    u_int len, Attrib *a)
+{
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, code);
+       buffer_put_int(&msg, id);
+       buffer_put_string(&msg, s, len);
+       encode_attrib(&msg, a);
+       send_msg(fd, &msg);
+       debug3("Sent message fd %d T:%d I:%d", fd, code, id);
+       buffer_free(&msg);
+}
+
+static u_int
+get_status(int fd, int expected_id)
+{
+       Buffer msg;
+       u_int type, id, status;
+
+       buffer_init(&msg);
+       get_msg(fd, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%d != %d)", id, expected_id);
+       if (type != SSH2_FXP_STATUS)
+               fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
+                   SSH2_FXP_STATUS, type);
+
+       status = buffer_get_int(&msg);
+       buffer_free(&msg);
+
+       debug3("SSH2_FXP_STATUS %d", status);
+
+       return(status);
+}
+
+static char *
+get_handle(int fd, u_int expected_id, u_int *len)
+{
+       Buffer msg;
+       u_int type, id;
+       char *handle;
+
+       buffer_init(&msg);
+       get_msg(fd, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%d != %d)", id, expected_id);
+       if (type == SSH2_FXP_STATUS) {
+               int status = buffer_get_int(&msg);
+
+               error("Couldn't get handle: %s", fx2txt(status));
+               return(NULL);
+       } else if (type != SSH2_FXP_HANDLE)
+               fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
+                   SSH2_FXP_HANDLE, type);
+
+       handle = buffer_get_string(&msg, len);
+       buffer_free(&msg);
+
+       return(handle);
+}
+
+static Attrib *
+get_decode_stat(int fd, u_int expected_id, int quiet)
+{
+       Buffer msg;
+       u_int type, id;
+       Attrib *a;
+
+       buffer_init(&msg);
+       get_msg(fd, &msg);
+
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       debug3("Received stat reply T:%d I:%d", type, id);
+       if (id != expected_id)
+               fatal("ID mismatch (%d != %d)", id, expected_id);
+       if (type == SSH2_FXP_STATUS) {
+               int status = buffer_get_int(&msg);
+
+               if (quiet)
+                       debug("Couldn't stat remote file: %s", fx2txt(status));
+               else
+                       error("Couldn't stat remote file: %s", fx2txt(status));
+               return(NULL);
+       } else if (type != SSH2_FXP_ATTRS) {
+               fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
+                   SSH2_FXP_ATTRS, type);
+       }
+       a = decode_attrib(&msg);
+       buffer_free(&msg);
+
+       return(a);
+}
+
+int
+do_init(int fd_in, int fd_out)
+{
+       int type, version;
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_INIT);
+       buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
+       send_msg(fd_out, &msg);
+
+       buffer_clear(&msg);
+
+       get_msg(fd_in, &msg);
+
+       /* Expecting a VERSION reply */
+       if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
+               error("Invalid packet back from SSH2_FXP_INIT (type %d)",
+                   type);
+               buffer_free(&msg);
+               return(-1);
+       }
+       version = buffer_get_int(&msg);
+
+       debug2("Remote version: %d", version);
+
+       /* Check for extensions */
+       while (buffer_len(&msg) > 0) {
+               char *name = buffer_get_string(&msg, NULL);
+               char *value = buffer_get_string(&msg, NULL);
+
+               debug2("Init extension: \"%s\"", name);
+               xfree(name);
+               xfree(value);
+       }
+
+       buffer_free(&msg);
+
+       return(version);
+}
+
+int
+do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
+{
+       u_int id, status;
+       Buffer msg;
+
+       buffer_init(&msg);
+
+       id = msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_CLOSE);
+       buffer_put_int(&msg, id);
+       buffer_put_string(&msg, handle, handle_len);
+       send_msg(fd_out, &msg);
+       debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't close file: %s", fx2txt(status));
+
+       buffer_free(&msg);
+
+       return(status);
+}
+
+
+static int
+do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
+    SFTP_DIRENT ***dir)
+{
+       Buffer msg;
+       u_int type, id, handle_len, i, expected_id, ents = 0;
+       char *handle;
+
+       id = msg_id++;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_OPENDIR);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, path);
+       send_msg(fd_out, &msg);
+
+       buffer_clear(&msg);
+
+       handle = get_handle(fd_in, id, &handle_len);
+       if (handle == NULL)
+               return(-1);
+
+       if (dir) {
+               ents = 0;
+               *dir = xmalloc(sizeof(**dir));
+               (*dir)[0] = NULL;
+       }
+       
+
+       for(;;) {
+               int count;
+
+               id = expected_id = msg_id++;
+
+               debug3("Sending SSH2_FXP_READDIR I:%d", id);
+
+               buffer_clear(&msg);
+               buffer_put_char(&msg, SSH2_FXP_READDIR);
+               buffer_put_int(&msg, id);
+               buffer_put_string(&msg, handle, handle_len);
+               send_msg(fd_out, &msg);
+
+               buffer_clear(&msg);
+
+               get_msg(fd_in, &msg);
+
+               type = buffer_get_char(&msg);
+               id = buffer_get_int(&msg);
+
+               debug3("Received reply T:%d I:%d", type, id);
+
+               if (id != expected_id)
+                       fatal("ID mismatch (%d != %d)", id, expected_id);
+
+               if (type == SSH2_FXP_STATUS) {
+                       int status = buffer_get_int(&msg);
+
+                       debug3("Received SSH2_FXP_STATUS %d", status);
+
+                       if (status == SSH2_FX_EOF) {
+                               break;
+                       } else {
+                               error("Couldn't read directory: %s",
+                                   fx2txt(status));
+                               do_close(fd_in, fd_out, handle, handle_len);
+                               return(status);
+                       }
+               } else if (type != SSH2_FXP_NAME)
+                       fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
+                           SSH2_FXP_NAME, type);
+
+               count = buffer_get_int(&msg);
+               if (count == 0)
+                       break;
+               debug3("Received %d SSH2_FXP_NAME responses", count);
+               for(i = 0; i < count; i++) {
+                       char *filename, *longname;
+                       Attrib *a;
+
+                       filename = buffer_get_string(&msg, NULL);
+                       longname = buffer_get_string(&msg, NULL);
+                       a = decode_attrib(&msg);
+
+                       if (printflag)
+                               printf("%s\n", longname);
+
+                       if (dir) {
+                               *dir = xrealloc(*dir, sizeof(**dir) *
+                                   (ents + 2));
+                               (*dir)[ents] = xmalloc(sizeof(***dir));
+                               (*dir)[ents]->filename = xstrdup(filename);
+                               (*dir)[ents]->longname = xstrdup(longname);
+                               memcpy(&(*dir)[ents]->a, a, sizeof(*a));
+                               (*dir)[++ents] = NULL;
+                       }
+
+                       xfree(filename);
+                       xfree(longname);
+               }
+       }
+
+       buffer_free(&msg);
+       do_close(fd_in, fd_out, handle, handle_len);
+       xfree(handle);
+
+       return(0);
+}
+
+int
+do_ls(int fd_in, int fd_out, char *path)
+{
+       return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
+}
+
+int
+do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
+{
+       return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
+}
+
+void free_sftp_dirents(SFTP_DIRENT **s)
+{
+       int i;
+       
+       for(i = 0; s[i]; i++) {
+               xfree(s[i]->filename);
+               xfree(s[i]->longname);
+               xfree(s[i]);
+       }
+       xfree(s);
+}
+
+int
+do_rm(int fd_in, int fd_out, char *path)
+{
+       u_int status, id;
+
+       debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
+
+       id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't delete file: %s", fx2txt(status));
+       return(status);
+}
+
+int
+do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
+{
+       u_int status, id;
+
+       id = msg_id++;
+       send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
+           strlen(path), a);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't create directory: %s", fx2txt(status));
+
+       return(status);
+}
+
+int
+do_rmdir(int fd_in, int fd_out, char *path)
+{
+       u_int status, id;
+
+       id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't remove directory: %s", fx2txt(status));
+
+       return(status);
+}
+
+Attrib *
+do_stat(int fd_in, int fd_out, char *path, int quiet)
+{
+       u_int id;
+
+       id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
+       return(get_decode_stat(fd_in, id, quiet));
+}
+
+Attrib *
+do_lstat(int fd_in, int fd_out, char *path, int quiet)
+{
+       u_int id;
+
+       id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
+       return(get_decode_stat(fd_in, id, quiet));
+}
+
+Attrib *
+do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
+{
+       u_int id;
+
+       id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
+       return(get_decode_stat(fd_in, id, quiet));
+}
+
+int
+do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
+{
+       u_int status, id;
+
+       id = msg_id++;
+       send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
+           strlen(path), a);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't setstat on \"%s\": %s", path,
+                   fx2txt(status));
+
+       return(status);
+}
+
+int
+do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
+    Attrib *a)
+{
+       u_int status, id;
+
+       id = msg_id++;
+       send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
+           handle_len, a);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't fsetstat: %s", fx2txt(status));
+
+       return(status);
+}
+
+char *
+do_realpath(int fd_in, int fd_out, char *path)
+{
+       Buffer msg;
+       u_int type, expected_id, count, id;
+       char *filename, *longname;
+       Attrib *a;
+
+       expected_id = id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
+
+       buffer_init(&msg);
+
+       get_msg(fd_in, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%d != %d)", id, expected_id);
+
+       if (type == SSH2_FXP_STATUS) {
+               u_int status = buffer_get_int(&msg);
+
+               error("Couldn't canonicalise: %s", fx2txt(status));
+               return(NULL);
+       } else if (type != SSH2_FXP_NAME)
+               fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
+                   SSH2_FXP_NAME, type);
+
+       count = buffer_get_int(&msg);
+       if (count != 1)
+               fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
+
+       filename = buffer_get_string(&msg, NULL);
+       longname = buffer_get_string(&msg, NULL);
+       a = decode_attrib(&msg);
+
+       debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
+
+       xfree(longname);
+
+       buffer_free(&msg);
+
+       return(filename);
+}
+
+int
+do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
+{
+       Buffer msg;
+       u_int status, id;
+
+       buffer_init(&msg);
+
+       /* Send rename request */
+       id = msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_RENAME);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, oldpath);
+       buffer_put_cstring(&msg, newpath);
+       send_msg(fd_out, &msg);
+       debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
+           newpath);
+       buffer_free(&msg);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
+                   fx2txt(status));
+
+       return(status);
+}
+
+int
+do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
+{
+       Buffer msg;
+       u_int status, id;
+
+       buffer_init(&msg);
+
+       /* Send rename request */
+       id = msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_SYMLINK);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, oldpath);
+       buffer_put_cstring(&msg, newpath);
+       send_msg(fd_out, &msg);
+       debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
+           newpath);
+       buffer_free(&msg);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
+                   fx2txt(status));
+
+       return(status);
+}
+
+char *
+do_readlink(int fd_in, int fd_out, char *path)
+{
+       Buffer msg;
+       u_int type, expected_id, count, id;
+       char *filename, *longname;
+       Attrib *a;
+
+       expected_id = id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
+
+       buffer_init(&msg);
+
+       get_msg(fd_in, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%d != %d)", id, expected_id);
+
+       if (type == SSH2_FXP_STATUS) {
+               u_int status = buffer_get_int(&msg);
+
+               error("Couldn't readlink: %s", fx2txt(status));
+               return(NULL);
+       } else if (type != SSH2_FXP_NAME)
+               fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
+                   SSH2_FXP_NAME, type);
+
+       count = buffer_get_int(&msg);
+       if (count != 1)
+               fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
+
+       filename = buffer_get_string(&msg, NULL);
+       longname = buffer_get_string(&msg, NULL);
+       a = decode_attrib(&msg);
+
+       debug3("SSH_FXP_READLINK %s -> %s", path, filename);
+
+       xfree(longname);
+
+       buffer_free(&msg);
+
+       return(filename);
+}
+
+int
+do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
+    int pflag)
+{
+       int local_fd;
+       u_int expected_id, handle_len, mode, type, id;
+       u_int64_t offset;
+       char *handle;
+       Buffer msg;
+       Attrib junk, *a;
+       int status;
+
+       a = do_stat(fd_in, fd_out, remote_path, 0);
+       if (a == NULL)
+               return(-1);
+
+       /* XXX: should we preserve set[ug]id? */
+       if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+               mode = S_IWRITE | (a->perm & 0777);
+       else
+               mode = 0666;
+
+       if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+           (a->perm & S_IFDIR)) {
+               error("Cannot download a directory: %s", remote_path);
+               return(-1);
+       }
+
+       local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+       if (local_fd == -1) {
+               error("Couldn't open local file \"%s\" for writing: %s",
+                   local_path, strerror(errno));
+               return(-1);
+       }
+
+       buffer_init(&msg);
+
+       /* Send open request */
+       id = msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_OPEN);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, remote_path);
+       buffer_put_int(&msg, SSH2_FXF_READ);
+       attrib_clear(&junk); /* Send empty attributes */
+       encode_attrib(&msg, &junk);
+       send_msg(fd_out, &msg);
+       debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
+
+       handle = get_handle(fd_in, id, &handle_len);
+       if (handle == NULL) {
+               buffer_free(&msg);
+               close(local_fd);
+               return(-1);
+       }
+
+       /* Read from remote and write to local */
+       offset = 0;
+       for(;;) {
+               u_int len;
+               char *data;
+
+               id = expected_id = msg_id++;
+
+               buffer_clear(&msg);
+               buffer_put_char(&msg, SSH2_FXP_READ);
+               buffer_put_int(&msg, id);
+               buffer_put_string(&msg, handle, handle_len);
+               buffer_put_int64(&msg, offset);
+               buffer_put_int(&msg, COPY_SIZE);
+               send_msg(fd_out, &msg);
+               debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
+                   id, (u_int64_t)offset, COPY_SIZE);
+
+               buffer_clear(&msg);
+
+               get_msg(fd_in, &msg);
+               type = buffer_get_char(&msg);
+               id = buffer_get_int(&msg);
+               debug3("Received reply T:%d I:%d", type, id);
+               if (id != expected_id)
+                       fatal("ID mismatch (%d != %d)", id, expected_id);
+               if (type == SSH2_FXP_STATUS) {
+                       status = buffer_get_int(&msg);
+
+                       if (status == SSH2_FX_EOF)
+                               break;
+                       else {
+                               error("Couldn't read from remote "
+                                   "file \"%s\" : %s", remote_path,
+                                    fx2txt(status));
+                               do_close(fd_in, fd_out, handle, handle_len);
+                               goto done;
+                       }
+               } else if (type != SSH2_FXP_DATA) {
+                       fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
+                           SSH2_FXP_DATA, type);
+               }
+
+               data = buffer_get_string(&msg, &len);
+               if (len > COPY_SIZE)
+                       fatal("Received more data than asked for %d > %d",
+                           len, COPY_SIZE);
+
+               debug3("In read loop, got %d offset %llu", len,
+                   (u_int64_t)offset);
+               if (atomicio(write, local_fd, data, len) != len) {
+                       error("Couldn't write to \"%s\": %s", local_path,
+                           strerror(errno));
+                       do_close(fd_in, fd_out, handle, handle_len);
+                       status = -1;
+                       xfree(data);
+                       goto done;
+               }
+
+               offset += len;
+               xfree(data);
+       }
+       status = do_close(fd_in, fd_out, handle, handle_len);
+
+       /* Override umask and utimes if asked */
+#ifdef HAVE_FCHMOD
+       if (pflag && fchmod(local_fd, mode) == -1)
+#else 
+       if (pflag && chmod(local_path, mode) == -1)
+#endif /* HAVE_FCHMOD */
+               error("Couldn't set mode on \"%s\": %s", local_path,
+                   strerror(errno));
+       if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
+               struct timeval tv[2];
+               tv[0].tv_sec = a->atime;
+               tv[1].tv_sec = a->mtime;
+               tv[0].tv_usec = tv[1].tv_usec = 0;
+               if (utimes(local_path, tv) == -1)
+                       error("Can't set times on \"%s\": %s", local_path,
+                           strerror(errno));
+       }
+
+done:
+       close(local_fd);
+       buffer_free(&msg);
+       xfree(handle);
+       return status;
+}
+
+int
+do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
+    int pflag)
+{
+       int local_fd;
+       u_int handle_len, id;
+       u_int64_t offset;
+       char *handle;
+       Buffer msg;
+       struct stat sb;
+       Attrib a;
+       int status;
+
+       if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
+               error("Couldn't open local file \"%s\" for reading: %s",
+                   local_path, strerror(errno));
+               return(-1);
+       }
+       if (fstat(local_fd, &sb) == -1) {
+               error("Couldn't fstat local file \"%s\": %s",
+                   local_path, strerror(errno));
+               close(local_fd);
+               return(-1);
+       }
+       stat_to_attrib(&sb, &a);
+
+       a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
+       a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
+       a.perm &= 0777;
+       if (!pflag)
+               a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
+
+       buffer_init(&msg);
+
+       /* Send open request */
+       id = msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_OPEN);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, remote_path);
+       buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
+       encode_attrib(&msg, &a);
+       send_msg(fd_out, &msg);
+       debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
+
+       buffer_clear(&msg);
+
+       handle = get_handle(fd_in, id, &handle_len);
+       if (handle == NULL) {
+               close(local_fd);
+               buffer_free(&msg);
+               return(-1);
+       }
+
+       /* Read from local and write to remote */
+       offset = 0;
+       for(;;) {
+               int len;
+               char data[COPY_SIZE];
+
+               /*
+                * Can't use atomicio here because it returns 0 on EOF, thus losing
+                * the last block of the file
+                */
+               do
+                       len = read(local_fd, data, COPY_SIZE);
+               while ((len == -1) && (errno == EINTR || errno == EAGAIN));
+
+               if (len == -1)
+                       fatal("Couldn't read from \"%s\": %s", local_path,
+                           strerror(errno));
+               if (len == 0)
+                       break;
+
+               buffer_clear(&msg);
+               buffer_put_char(&msg, SSH2_FXP_WRITE);
+               buffer_put_int(&msg, ++id);
+               buffer_put_string(&msg, handle, handle_len);
+               buffer_put_int64(&msg, offset);
+               buffer_put_string(&msg, data, len);
+               send_msg(fd_out, &msg);
+               debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
+                   id, (u_int64_t)offset, len);
+
+               status = get_status(fd_in, id);
+               if (status != SSH2_FX_OK) {
+                       error("Couldn't write to remote file \"%s\": %s",
+                           remote_path, fx2txt(status));
+                       do_close(fd_in, fd_out, handle, handle_len);
+                       close(local_fd);
+                       goto done;
+               }
+               debug3("In write loop, got %d offset %llu", len,
+                   (u_int64_t)offset);
+
+               offset += len;
+       }
+
+       if (close(local_fd) == -1) {
+               error("Couldn't close local file \"%s\": %s", local_path,
+                   strerror(errno));
+               do_close(fd_in, fd_out, handle, handle_len);
+               status = -1;
+               goto done;
+       }
+
+       /* Override umask and utimes if asked */
+       if (pflag)
+               do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
+
+       status = do_close(fd_in, fd_out, handle, handle_len);
+
+done:
+       xfree(handle);
+       buffer_free(&msg);
+       return status;
+}
+
diff --git a/openssh/sftp-client.h b/openssh/sftp-client.h
new file mode 100644 (file)
index 0000000..a322b25
--- /dev/null
@@ -0,0 +1,103 @@
+/* $OpenBSD: sftp-client.h,v 1.6 2001/06/26 06:33:01 itojun Exp $ */
+
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Client side of SSH2 filexfer protocol */
+
+typedef struct SFTP_DIRENT SFTP_DIRENT;
+
+struct SFTP_DIRENT {
+       char *filename;
+       char *longname;
+       Attrib a;
+};
+
+/*
+ * Initialiase a SSH filexfer connection. Returns -1 on error or
+ * protocol version on success.
+ */
+int do_init(int, int);
+
+/* Close file referred to by 'handle' */
+int do_close(int, int, char *, u_int);
+
+/* List contents of directory 'path' to stdout */
+int do_ls(int, int, char *);
+
+/* Read contents of 'path' to NULL-terminated array 'dir' */
+int do_readdir(int, int, char *, SFTP_DIRENT ***);
+
+/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
+void free_sftp_dirents(SFTP_DIRENT **);
+
+/* Delete file 'path' */
+int do_rm(int, int, char *);
+
+/* Create directory 'path' */
+int do_mkdir(int, int, char *, Attrib *);
+
+/* Remove directory 'path' */
+int do_rmdir(int, int, char *);
+
+/* Get file attributes of 'path' (follows symlinks) */
+Attrib *do_stat(int, int, char *, int);
+
+/* Get file attributes of 'path' (does not follow symlinks) */
+Attrib *do_lstat(int, int, char *, int);
+
+/* Get file attributes of open file 'handle' */
+Attrib *do_fstat(int, int, char *, u_int, int);
+
+/* Set file attributes of 'path' */
+int do_setstat(int, int, char *, Attrib *);
+
+/* Set file attributes of open file 'handle' */
+int do_fsetstat(int, int, char *, u_int, Attrib *);
+
+/* Canonicalise 'path' - caller must free result */
+char *do_realpath(int, int, char *);
+
+/* Rename 'oldpath' to 'newpath' */
+int do_rename(int, int, char *, char *);
+
+/* Rename 'oldpath' to 'newpath' */
+int do_symlink(int, int, char *, char *);
+
+/* Return target of symlink 'path' - caller must free result */
+char *do_readlink(int, int, char *);
+
+/* XXX: add callbacks to do_download/do_upload so we can do progress meter */
+
+/*
+ * Download 'remote_path' to 'local_path'. Preserve permissions and times
+ * if 'pflag' is set
+ */
+int do_download(int, int, char *, char *, int);
+
+/*
+ * Upload 'local_path' to 'remote_path'. Preserve permissions and times
+ * if 'pflag' is set
+ */
+int do_upload(int, int, char *, char *, int);
diff --git a/openssh/sftp-common.c b/openssh/sftp-common.c
new file mode 100644 (file)
index 0000000..9235048
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sftp-common.c,v 1.4 2001/07/14 15:10:17 stevesk Exp $");
+
+#include "buffer.h"
+#include "bufaux.h"
+#include "log.h"
+#include "xmalloc.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+
+/* Clear contents of attributes structure */
+void
+attrib_clear(Attrib *a)
+{
+       a->flags = 0;
+       a->size = 0;
+       a->uid = 0;
+       a->gid = 0;
+       a->perm = 0;
+       a->atime = 0;
+       a->mtime = 0;
+}
+
+/* Convert from struct stat to filexfer attribs */
+void
+stat_to_attrib(struct stat *st, Attrib *a)
+{
+       attrib_clear(a);
+       a->flags = 0;
+       a->flags |= SSH2_FILEXFER_ATTR_SIZE;
+       a->size = st->st_size;
+       a->flags |= SSH2_FILEXFER_ATTR_UIDGID;
+       a->uid = st->st_uid;
+       a->gid = st->st_gid;
+       a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
+       a->perm = st->st_mode;
+       a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
+       a->atime = st->st_atime;
+       a->mtime = st->st_mtime;
+}
+
+/* Decode attributes in buffer */
+Attrib *
+decode_attrib(Buffer *b)
+{
+       static Attrib a;
+       attrib_clear(&a);
+       a.flags = buffer_get_int(b);
+       if (a.flags & SSH2_FILEXFER_ATTR_SIZE)
+               a.size = buffer_get_int64(b);
+       if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
+               a.uid = buffer_get_int(b);
+               a.gid = buffer_get_int(b);
+       }
+       if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+               a.perm = buffer_get_int(b);
+       if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+               a.atime = buffer_get_int(b);
+               a.mtime = buffer_get_int(b);
+       }
+       /* vendor-specific extensions */
+       if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) {
+               char *type, *data;
+               int i, count;
+               count = buffer_get_int(b);
+               for (i = 0; i < count; i++) {
+                       type = buffer_get_string(b, NULL);
+                       data = buffer_get_string(b, NULL);
+                       debug3("Got file attribute \"%s\"", type);
+                       xfree(type);
+                       xfree(data);
+               }
+       }
+       return &a;
+}
+
+/* Encode attributes to buffer */
+void
+encode_attrib(Buffer *b, Attrib *a)
+{
+       buffer_put_int(b, a->flags);
+       if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
+               buffer_put_int64(b, a->size);
+       if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+               buffer_put_int(b, a->uid);
+               buffer_put_int(b, a->gid);
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+               buffer_put_int(b, a->perm);
+       if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+               buffer_put_int(b, a->atime);
+               buffer_put_int(b, a->mtime);
+       }
+}
+
+/* Convert from SSH2_FX_ status to text error message */
+const char *
+fx2txt(int status)
+{
+       switch (status) {
+       case SSH2_FX_OK:
+               return("No error");
+       case SSH2_FX_EOF:
+               return("End of file");
+       case SSH2_FX_NO_SUCH_FILE:
+               return("No such file or directory");
+       case SSH2_FX_PERMISSION_DENIED:
+               return("Permission denied");
+       case SSH2_FX_FAILURE:
+               return("Failure");
+       case SSH2_FX_BAD_MESSAGE:
+               return("Bad message");
+       case SSH2_FX_NO_CONNECTION:
+               return("No connection");
+       case SSH2_FX_CONNECTION_LOST:
+               return("Connection lost");
+       case SSH2_FX_OP_UNSUPPORTED:
+               return("Operation unsupported");
+       default:
+               return("Unknown status");
+       };
+       /* NOTREACHED */
+}
diff --git a/openssh/sftp-common.h b/openssh/sftp-common.h
new file mode 100644 (file)
index 0000000..4c126bf
--- /dev/null
@@ -0,0 +1,46 @@
+/*     $OpenBSD: sftp-common.h,v 1.3 2001/06/26 17:27:24 markus Exp $  */
+
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+typedef struct Attrib Attrib;
+
+/* File attributes */
+struct Attrib {
+       u_int32_t       flags;
+       u_int64_t       size;
+       u_int32_t       uid;
+       u_int32_t       gid;
+       u_int32_t       perm;
+       u_int32_t       atime;
+       u_int32_t       mtime;
+};
+
+void    attrib_clear(Attrib *);
+void    stat_to_attrib(struct stat *, Attrib *);
+Attrib *decode_attrib(Buffer *);
+void    encode_attrib(Buffer *, Attrib *);
+
+const char *fx2txt(int);
diff --git a/openssh/sftp-glob.c b/openssh/sftp-glob.c
new file mode 100644 (file)
index 0000000..a432bdf
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sftp-glob.c,v 1.8 2001/07/14 15:10:17 stevesk Exp $");
+
+#include "buffer.h"
+#include "bufaux.h"
+#include "xmalloc.h"
+#include "log.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+#include "sftp-client.h"
+#include "sftp-glob.h"
+
+struct SFTP_OPENDIR {
+       SFTP_DIRENT **dir;
+       int offset;
+};
+
+static struct {
+       int fd_in;
+       int fd_out;
+} cur;
+
+static void *
+fudge_opendir(const char *path)
+{
+       struct SFTP_OPENDIR *r;
+       
+       r = xmalloc(sizeof(*r));
+       
+       if (do_readdir(cur.fd_in, cur.fd_out, (char*)path, &r->dir))
+               return(NULL);
+
+       r->offset = 0;
+
+       return((void*)r);
+}
+
+static struct dirent *
+fudge_readdir(struct SFTP_OPENDIR *od)
+{
+       /* Solaris needs sizeof(dirent) + path length (see below) */
+       static char buf[sizeof(struct dirent) + MAXPATHLEN];
+       struct dirent *ret = (struct dirent *)buf;
+#ifdef __GNU_LIBRARY__
+       static int inum = 1;
+#endif /* __GNU_LIBRARY__ */
+       
+       if (od->dir[od->offset] == NULL)
+               return(NULL);
+
+       memset(buf, 0, sizeof(buf));
+
+       /*
+        * Solaris defines dirent->d_name as a one byte array and expects
+        * you to hack around it.
+        */
+#ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME
+       strlcpy(ret->d_name, od->dir[od->offset++]->filename, MAXPATHLEN);
+#else
+       strlcpy(ret->d_name, od->dir[od->offset++]->filename,
+           sizeof(ret->d_name));
+#endif
+#ifdef __GNU_LIBRARY__
+       /*
+        * Idiot glibc uses extensions to struct dirent for readdir with
+        * ALTDIRFUNCs. Not that this is documented anywhere but the 
+        * source... Fake an inode number to appease it.
+        */
+       ret->d_ino = inum++;
+       if (!inum)
+               inum = 1;
+#endif /* __GNU_LIBRARY__ */
+
+       return(ret);
+}
+
+static void
+fudge_closedir(struct SFTP_OPENDIR *od)
+{
+       free_sftp_dirents(od->dir);
+       xfree(od);
+}
+
+static void
+attrib_to_stat(Attrib *a, struct stat *st)
+{
+       memset(st, 0, sizeof(*st));
+       
+       if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
+               st->st_size = a->size;
+       if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+               st->st_uid = a->uid;
+               st->st_gid = a->gid;
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+               st->st_mode = a->perm;
+       if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+               st->st_atime = a->atime;
+               st->st_mtime = a->mtime;
+       }
+}
+
+static int
+fudge_lstat(const char *path, struct stat *st)
+{
+       Attrib *a;
+       
+       if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0)))
+               return(-1);
+       
+       attrib_to_stat(a, st);
+       
+       return(0);
+}
+
+static int
+fudge_stat(const char *path, struct stat *st)
+{
+       Attrib *a;
+       
+       if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0)))
+               return(-1);
+       
+       attrib_to_stat(a, st);
+       
+       return(0);
+}
+
+int
+remote_glob(int fd_in, int fd_out, const char *pattern, int flags,
+    int (*errfunc)(const char *, int), glob_t *pglob)
+{
+       pglob->gl_opendir = fudge_opendir;
+       pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir;
+       pglob->gl_closedir = (void (*)(void *))fudge_closedir;
+       pglob->gl_lstat = fudge_lstat;
+       pglob->gl_stat = fudge_stat;
+       
+       memset(&cur, 0, sizeof(cur));
+       cur.fd_in = fd_in;
+       cur.fd_out = fd_out;
+
+       return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc,
+           pglob));
+}
diff --git a/openssh/sftp-glob.h b/openssh/sftp-glob.h
new file mode 100644 (file)
index 0000000..2885044
--- /dev/null
@@ -0,0 +1,30 @@
+/* $OpenBSD: sftp-glob.h,v 1.5 2001/06/26 17:27:24 markus Exp $ */
+
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Remote sftp filename globbing */
+
+int
+remote_glob(int, int, const char *, int, int (*)(const char *, int), glob_t *);
diff --git a/openssh/sftp-int.c b/openssh/sftp-int.c
new file mode 100644 (file)
index 0000000..841e562
--- /dev/null
@@ -0,0 +1,922 @@
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* XXX: globbed ls */
+/* XXX: recursive operations */
+
+#include "includes.h"
+RCSID("$OpenBSD: sftp-int.c,v 1.40 2001/08/14 09:23:02 markus Exp $");
+
+#include "buffer.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "pathnames.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+#include "sftp-glob.h"
+#include "sftp-client.h"
+#include "sftp-int.h"
+
+/* File to read commands from */
+extern FILE *infile;
+
+/* Version of server we are speaking to */
+int version;
+
+/* Seperators for interactive commands */
+#define WHITESPACE " \t\r\n"
+
+/* Commands for interactive mode */
+#define I_CHDIR                1
+#define I_CHGRP                2
+#define I_CHMOD                3
+#define I_CHOWN                4
+#define I_GET          5
+#define I_HELP         6
+#define I_LCHDIR       7
+#define I_LLS          8
+#define I_LMKDIR       9
+#define I_LPWD         10
+#define I_LS           11
+#define I_LUMASK       12
+#define I_MKDIR                13
+#define I_PUT          14
+#define I_PWD          15
+#define I_QUIT         16
+#define I_RENAME       17
+#define I_RM           18
+#define I_RMDIR                19
+#define I_SHELL                20
+#define I_SYMLINK      21
+#define I_VERSION      22
+
+struct CMD {
+       const char *c;
+       const int n;
+};
+
+const struct CMD cmds[] = {
+       { "bye",        I_QUIT },
+       { "cd",         I_CHDIR },
+       { "chdir",      I_CHDIR },
+       { "chgrp",      I_CHGRP },
+       { "chmod",      I_CHMOD },
+       { "chown",      I_CHOWN },
+       { "dir",        I_LS },
+       { "exit",       I_QUIT },
+       { "get",        I_GET },
+       { "mget",       I_GET },
+       { "help",       I_HELP },
+       { "lcd",        I_LCHDIR },
+       { "lchdir",     I_LCHDIR },
+       { "lls",        I_LLS },
+       { "lmkdir",     I_LMKDIR },
+       { "ln",         I_SYMLINK },
+       { "lpwd",       I_LPWD },
+       { "ls",         I_LS },
+       { "lumask",     I_LUMASK },
+       { "mkdir",      I_MKDIR },
+       { "put",        I_PUT },
+       { "mput",       I_PUT },
+       { "pwd",        I_PWD },
+       { "quit",       I_QUIT },
+       { "rename",     I_RENAME },
+       { "rm",         I_RM },
+       { "rmdir",      I_RMDIR },
+       { "symlink",    I_SYMLINK },
+       { "version",    I_VERSION },
+       { "!",          I_SHELL },
+       { "?",          I_HELP },
+       { NULL,                 -1}
+};
+
+static void
+help(void)
+{
+       printf("Available commands:\n");
+       printf("cd path                       Change remote directory to 'path'\n");
+       printf("lcd path                      Change local directory to 'path'\n");
+       printf("chgrp grp path                Change group of file 'path' to 'grp'\n");
+       printf("chmod mode path               Change permissions of file 'path' to 'mode'\n");
+       printf("chown own path                Change owner of file 'path' to 'own'\n");
+       printf("help                          Display this help text\n");
+       printf("get remote-path [local-path]  Download file\n");
+       printf("lls [ls-options [path]]       Display local directory listing\n");
+       printf("ln oldpath newpath            Symlink remote file\n");
+       printf("lmkdir path                   Create local directory\n");
+       printf("lpwd                          Print local working directory\n");
+       printf("ls [path]                     Display remote directory listing\n");
+       printf("lumask umask                  Set local umask to 'umask'\n");
+       printf("mkdir path                    Create remote directory\n");
+       printf("put local-path [remote-path]  Upload file\n");
+       printf("pwd                           Display remote working directory\n");
+       printf("exit                          Quit sftp\n");
+       printf("quit                          Quit sftp\n");
+       printf("rename oldpath newpath        Rename remote file\n");
+       printf("rmdir path                    Remove remote directory\n");
+       printf("rm path                       Delete remote file\n");
+       printf("symlink oldpath newpath       Symlink remote file\n");
+       printf("version                       Show SFTP version\n");
+       printf("!command                      Execute 'command' in local shell\n");
+       printf("!                             Escape to local shell\n");
+       printf("?                             Synonym for help\n");
+}
+
+static void
+local_do_shell(const char *args)
+{
+       int status;
+       char *shell;
+       pid_t pid;
+
+       if (!*args)
+               args = NULL;
+
+       if ((shell = getenv("SHELL")) == NULL)
+               shell = _PATH_BSHELL;
+
+       if ((pid = fork()) == -1)
+               fatal("Couldn't fork: %s", strerror(errno));
+
+       if (pid == 0) {
+               /* XXX: child has pipe fds to ssh subproc open - issue? */
+               if (args) {
+                       debug3("Executing %s -c \"%s\"", shell, args);
+                       execl(shell, shell, "-c", args, (char *)NULL);
+               } else {
+                       debug3("Executing %s", shell);
+                       execl(shell, shell, (char *)NULL);
+               }
+               fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
+                   strerror(errno));
+               _exit(1);
+       }
+       if (waitpid(pid, &status, 0) == -1)
+               fatal("Couldn't wait for child: %s", strerror(errno));
+       if (!WIFEXITED(status))
+               error("Shell exited abormally");
+       else if (WEXITSTATUS(status))
+               error("Shell exited with status %d", WEXITSTATUS(status));
+}
+
+static void
+local_do_ls(const char *args)
+{
+       if (!args || !*args)
+               local_do_shell(_PATH_LS);
+       else {
+               int len = strlen(_PATH_LS " ") + strlen(args) + 1;
+               char *buf = xmalloc(len);
+
+               /* XXX: quoting - rip quoting code from ftp? */
+               snprintf(buf, len, _PATH_LS " %s", args);
+               local_do_shell(buf);
+               xfree(buf);
+       }
+}
+
+static char *
+path_append(char *p1, char *p2)
+{
+       char *ret;
+       int len = strlen(p1) + strlen(p2) + 2;
+
+       ret = xmalloc(len);
+       strlcpy(ret, p1, len);
+       if (strcmp(p1, "/") != 0) 
+               strlcat(ret, "/", len);
+       strlcat(ret, p2, len);
+
+       return(ret);
+}
+
+static char *
+make_absolute(char *p, char *pwd)
+{
+       char *abs;
+
+       /* Derelativise */
+       if (p && p[0] != '/') {
+               abs = path_append(pwd, p);
+               xfree(p);
+               return(abs);
+       } else
+               return(p);
+}
+
+static int
+infer_path(const char *p, char **ifp)
+{
+       char *cp;
+
+       cp = strrchr(p, '/');
+       if (cp == NULL) {
+               *ifp = xstrdup(p);
+               return(0);
+       }
+
+       if (!cp[1]) {
+               error("Invalid path");
+               return(-1);
+       }
+
+       *ifp = xstrdup(cp + 1);
+       return(0);
+}
+
+static int
+parse_getput_flags(const char **cpp, int *pflag)
+{
+       const char *cp = *cpp;
+
+       /* Check for flags */
+       if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) {
+               switch (cp[1]) {
+               case 'p':
+               case 'P':
+                       *pflag = 1;
+                       break;
+               default:
+                       error("Invalid flag -%c", cp[1]);
+                       return(-1);
+               }
+               cp += 2;
+               *cpp = cp + strspn(cp, WHITESPACE);
+       }
+
+       return(0);
+}
+
+static int
+get_pathname(const char **cpp, char **path)
+{
+       const char *cp = *cpp, *end;
+       char quot;
+       int i;
+
+       cp += strspn(cp, WHITESPACE);
+       if (!*cp) {
+               *cpp = cp;
+               *path = NULL;
+               return (0);
+       }
+
+       /* Check for quoted filenames */
+       if (*cp == '\"' || *cp == '\'') {
+               quot = *cp++;
+
+               end = strchr(cp, quot);
+               if (end == NULL) {
+                       error("Unterminated quote");
+                       goto fail;
+               }
+               if (cp == end) {
+                       error("Empty quotes");
+                       goto fail;
+               }
+               *cpp = end + 1 + strspn(end + 1, WHITESPACE);
+       } else {
+               /* Read to end of filename */
+               end = strpbrk(cp, WHITESPACE);
+               if (end == NULL)
+                       end = strchr(cp, '\0');
+               *cpp = end + strspn(end, WHITESPACE);
+       }
+
+       i = end - cp;
+
+       *path = xmalloc(i + 1);
+       memcpy(*path, cp, i);
+       (*path)[i] = '\0';
+       return(0);
+
+ fail:
+       *path = NULL;
+       return (-1);
+}
+
+static int
+is_dir(char *path)
+{
+       struct stat sb;
+
+       /* XXX: report errors? */
+       if (stat(path, &sb) == -1)
+               return(0);
+
+       return(sb.st_mode & S_IFDIR);
+}
+
+static int
+remote_is_dir(int in, int out, char *path)
+{
+       Attrib *a;
+
+       /* XXX: report errors? */
+       if ((a = do_stat(in, out, path, 1)) == NULL)
+               return(0);
+       if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
+               return(0);
+       return(a->perm & S_IFDIR);
+}
+
+static int
+process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
+{
+       char *abs_src = NULL;
+       char *abs_dst = NULL;
+       char *tmp;
+       glob_t g;
+       int err = 0;
+       int i;
+
+       abs_src = xstrdup(src);
+       abs_src = make_absolute(abs_src, pwd);
+
+       memset(&g, 0, sizeof(g));
+       debug3("Looking up %s", abs_src);
+       if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
+               error("File \"%s\" not found.", abs_src);
+               err = -1;
+               goto out;
+       }
+
+       /* Only one match, dst may be file, directory or unspecified */
+       if (g.gl_pathv[0] && g.gl_matchc == 1) {
+               if (dst) {
+                       /* If directory specified, append filename */
+                       if (is_dir(dst)) {
+                               if (infer_path(g.gl_pathv[0], &tmp)) {
+                                       err = 1;
+                                       goto out;
+                               }
+                               abs_dst = path_append(dst, tmp);
+                               xfree(tmp);
+                       } else
+                               abs_dst = xstrdup(dst);
+               } else if (infer_path(g.gl_pathv[0], &abs_dst)) {
+                       err = -1;
+                       goto out;
+               }
+               printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
+               err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
+               goto out;
+       }
+
+       /* Multiple matches, dst may be directory or unspecified */
+       if (dst && !is_dir(dst)) {
+               error("Multiple files match, but \"%s\" is not a directory",
+                   dst);
+               err = -1;
+               goto out;
+       }
+
+       for(i = 0; g.gl_pathv[i]; i++) {
+               if (infer_path(g.gl_pathv[i], &tmp)) {
+                       err = -1;
+                       goto out;
+               }
+               if (dst) {
+                       abs_dst = path_append(dst, tmp);
+                       xfree(tmp);
+               } else
+                       abs_dst = tmp;
+
+               printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
+               if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
+                       err = -1;
+               xfree(abs_dst);
+               abs_dst = NULL;
+       }
+
+out:
+       xfree(abs_src);
+       if (abs_dst)
+               xfree(abs_dst);
+       globfree(&g);
+       return(err);
+}
+
+static int
+process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
+{
+       char *tmp_dst = NULL;
+       char *abs_dst = NULL;
+       char *tmp;
+       glob_t g;
+       int err = 0;
+       int i;
+
+       if (dst) {
+               tmp_dst = xstrdup(dst);
+               tmp_dst = make_absolute(tmp_dst, pwd);
+       }
+
+       memset(&g, 0, sizeof(g));
+       debug3("Looking up %s", src);
+       if (glob(src, 0, NULL, &g)) {
+               error("File \"%s\" not found.", src);
+               err = -1;
+               goto out;
+       }
+
+       /* Only one match, dst may be file, directory or unspecified */
+       if (g.gl_pathv[0] && g.gl_matchc == 1) {
+               if (tmp_dst) {
+                       /* If directory specified, append filename */
+                       if (remote_is_dir(in, out, tmp_dst)) {
+                               if (infer_path(g.gl_pathv[0], &tmp)) {
+                                       err = 1;
+                                       goto out;
+                               }
+                               abs_dst = path_append(tmp_dst, tmp);
+                               xfree(tmp);
+                       } else
+                               abs_dst = xstrdup(tmp_dst);
+               } else {
+                       if (infer_path(g.gl_pathv[0], &abs_dst)) {
+                               err = -1;
+                               goto out;
+                       }
+                       abs_dst = make_absolute(abs_dst, pwd);
+               }
+               printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
+               err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
+               goto out;
+       }
+
+       /* Multiple matches, dst may be directory or unspecified */
+       if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
+               error("Multiple files match, but \"%s\" is not a directory",
+                   tmp_dst);
+               err = -1;
+               goto out;
+       }
+
+       for(i = 0; g.gl_pathv[i]; i++) {
+               if (infer_path(g.gl_pathv[i], &tmp)) {
+                       err = -1;
+                       goto out;
+               }
+               if (tmp_dst) {
+                       abs_dst = path_append(tmp_dst, tmp);
+                       xfree(tmp);
+               } else
+                       abs_dst = make_absolute(tmp, pwd);
+
+               printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
+               if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
+                       err = -1;
+       }
+
+out:
+       if (abs_dst)
+               xfree(abs_dst);
+       if (tmp_dst)
+               xfree(tmp_dst);
+       return(err);
+}
+
+static int
+parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
+    char **path1, char **path2)
+{
+       const char *cmd, *cp = *cpp;
+       char *cp2;
+       int base = 0;
+       long l;
+       int i, cmdnum;
+
+       /* Skip leading whitespace */
+       cp = cp + strspn(cp, WHITESPACE);
+
+       /* Ignore blank lines */
+       if (!*cp)
+               return(-1);
+
+       /* Figure out which command we have */
+       for(i = 0; cmds[i].c; i++) {
+               int cmdlen = strlen(cmds[i].c);
+
+               /* Check for command followed by whitespace */
+               if (!strncasecmp(cp, cmds[i].c, cmdlen) &&
+                   strchr(WHITESPACE, cp[cmdlen])) {
+                       cp += cmdlen;
+                       cp = cp + strspn(cp, WHITESPACE);
+                       break;
+               }
+       }
+       cmdnum = cmds[i].n;
+       cmd = cmds[i].c;
+
+       /* Special case */
+       if (*cp == '!') {
+               cp++;
+               cmdnum = I_SHELL;
+       } else if (cmdnum == -1) {
+               error("Invalid command.");
+               return(-1);
+       }
+
+       /* Get arguments and parse flags */
+       *pflag = *n_arg = 0;
+       *path1 = *path2 = NULL;
+       switch (cmdnum) {
+       case I_GET:
+       case I_PUT:
+               if (parse_getput_flags(&cp, pflag))
+                       return(-1);
+               /* Get first pathname (mandatory) */
+               if (get_pathname(&cp, path1))
+                       return(-1);
+               if (*path1 == NULL) {
+                       error("You must specify at least one path after a "
+                           "%s command.", cmd);
+                       return(-1);
+               }
+               /* Try to get second pathname (optional) */
+               if (get_pathname(&cp, path2))
+                       return(-1);
+               break;
+       case I_RENAME:
+       case I_SYMLINK:
+               if (get_pathname(&cp, path1))
+                       return(-1);
+               if (get_pathname(&cp, path2))
+                       return(-1);
+               if (!*path1 || !*path2) {
+                       error("You must specify two paths after a %s "
+                           "command.", cmd);
+                       return(-1);
+               }
+               break;
+       case I_RM:
+       case I_MKDIR:
+       case I_RMDIR:
+       case I_CHDIR:
+       case I_LCHDIR:
+       case I_LMKDIR:
+               /* Get pathname (mandatory) */
+               if (get_pathname(&cp, path1))
+                       return(-1);
+               if (*path1 == NULL) {
+                       error("You must specify a path after a %s command.",
+                           cmd);
+                       return(-1);
+               }
+               break;
+       case I_LS:
+               /* Path is optional */
+               if (get_pathname(&cp, path1))
+                       return(-1);
+               break;
+       case I_LLS:
+       case I_SHELL:
+               /* Uses the rest of the line */
+               break;
+       case I_LUMASK:
+               base = 8;
+       case I_CHMOD:
+               base = 8;
+       case I_CHOWN:
+       case I_CHGRP:
+               /* Get numeric arg (mandatory) */
+               l = strtol(cp, &cp2, base);
+               if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) &&
+                   errno == ERANGE) || l < 0) {
+                       error("You must supply a numeric argument "
+                           "to the %s command.", cmd);
+                       return(-1);
+               }
+               cp = cp2;
+               *n_arg = l;
+               if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp))
+                       break;
+               if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) {
+                       error("You must supply a numeric argument "
+                           "to the %s command.", cmd);
+                       return(-1);
+               }
+               cp += strspn(cp, WHITESPACE);
+
+               /* Get pathname (mandatory) */
+               if (get_pathname(&cp, path1))
+                       return(-1);
+               if (*path1 == NULL) {
+                       error("You must specify a path after a %s command.",
+                           cmd);
+                       return(-1);
+               }
+               break;
+       case I_QUIT:
+       case I_PWD:
+       case I_LPWD:
+       case I_HELP:
+       case I_VERSION:
+               break;
+       default:
+               fatal("Command not implemented");
+       }
+
+       *cpp = cp;
+       return(cmdnum);
+}
+
+static int
+parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
+{
+       char *path1, *path2, *tmp;
+       int pflag, cmdnum, i;
+       unsigned long n_arg;
+       Attrib a, *aa;
+       char path_buf[MAXPATHLEN];
+       int err = 0;
+       glob_t g;
+
+       path1 = path2 = NULL;
+       cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
+
+       memset(&g, 0, sizeof(g));
+
+       /* Perform command */
+       switch (cmdnum) {
+       case -1:
+               break;
+       case I_GET:
+               err = process_get(in, out, path1, path2, *pwd, pflag);
+               break;
+       case I_PUT:
+               err = process_put(in, out, path1, path2, *pwd, pflag);
+               break;
+       case I_RENAME:
+               path1 = make_absolute(path1, *pwd);
+               path2 = make_absolute(path2, *pwd);
+               err = do_rename(in, out, path1, path2);
+               break;
+       case I_SYMLINK:
+               if (version < 3) {
+                       error("The server (version %d) does not support "
+                           "this operation", version);
+                       err = -1;
+               } else {
+                       path2 = make_absolute(path2, *pwd);
+                       err = do_symlink(in, out, path1, path2);
+               }
+               break;
+       case I_RM:
+               path1 = make_absolute(path1, *pwd);
+               remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+               for(i = 0; g.gl_pathv[i]; i++) {
+                       printf("Removing %s\n", g.gl_pathv[i]);
+                       if (do_rm(in, out, g.gl_pathv[i]) == -1)
+                               err = -1;
+               }
+               break;
+       case I_MKDIR:
+               path1 = make_absolute(path1, *pwd);
+               attrib_clear(&a);
+               a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
+               a.perm = 0777;
+               err = do_mkdir(in, out, path1, &a);
+               break;
+       case I_RMDIR:
+               path1 = make_absolute(path1, *pwd);
+               err = do_rmdir(in, out, path1);
+               break;
+       case I_CHDIR:
+               path1 = make_absolute(path1, *pwd);
+               if ((tmp = do_realpath(in, out, path1)) == NULL) {
+                       err = 1;
+                       break;
+               }
+               if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
+                       xfree(tmp);
+                       err = 1;
+                       break;
+               }
+               if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
+                       error("Can't change directory: Can't check target");
+                       xfree(tmp);
+                       err = 1;
+                       break;
+               }
+               if (!S_ISDIR(aa->perm)) {
+                       error("Can't change directory: \"%s\" is not "
+                           "a directory", tmp);
+                       xfree(tmp);
+                       err = 1;
+                       break;
+               }
+               xfree(*pwd);
+               *pwd = tmp;
+               break;
+       case I_LS:
+               if (!path1) {
+                       do_ls(in, out, *pwd);
+                       break;
+               }
+               path1 = make_absolute(path1, *pwd);
+               if ((tmp = do_realpath(in, out, path1)) == NULL)
+                       break;
+               xfree(path1);
+               path1 = tmp;
+               if ((aa = do_stat(in, out, path1, 0)) == NULL)
+                       break;
+               if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+                   !S_ISDIR(aa->perm)) {
+                       error("Can't ls: \"%s\" is not a directory", path1);
+                       break;
+               }
+               do_ls(in, out, path1);
+               break;
+       case I_LCHDIR:
+               if (chdir(path1) == -1) {
+                       error("Couldn't change local directory to "
+                           "\"%s\": %s", path1, strerror(errno));
+                       err = 1;
+               }
+               break;
+       case I_LMKDIR:
+               if (mkdir(path1, 0777) == -1) {
+                       error("Couldn't create local directory "
+                           "\"%s\": %s", path1, strerror(errno));
+                       err = 1;
+               }
+               break;
+       case I_LLS:
+               local_do_ls(cmd);
+               break;
+       case I_SHELL:
+               local_do_shell(cmd);
+               break;
+       case I_LUMASK:
+               umask(n_arg);
+               printf("Local umask: %03lo\n", n_arg);
+               break;
+       case I_CHMOD:
+               path1 = make_absolute(path1, *pwd);
+               attrib_clear(&a);
+               a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
+               a.perm = n_arg;
+               remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+               for(i = 0; g.gl_pathv[i]; i++) {
+                       printf("Changing mode on %s\n", g.gl_pathv[i]);
+                       do_setstat(in, out, g.gl_pathv[i], &a);
+               }
+               break;
+       case I_CHOWN:
+               path1 = make_absolute(path1, *pwd);
+               remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+               for(i = 0; g.gl_pathv[i]; i++) {
+                       if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
+                               continue;
+                       if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
+                               error("Can't get current ownership of "
+                                   "remote file \"%s\"", g.gl_pathv[i]);
+                               continue;
+                       }
+                       printf("Changing owner on %s\n", g.gl_pathv[i]);
+                       aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
+                       aa->uid = n_arg;
+                       do_setstat(in, out, g.gl_pathv[i], aa);
+               }
+               break;
+       case I_CHGRP:
+               path1 = make_absolute(path1, *pwd);
+               remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
+               for(i = 0; g.gl_pathv[i]; i++) {
+                       if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
+                               continue;
+                       if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
+                               error("Can't get current ownership of "
+                                   "remote file \"%s\"", g.gl_pathv[i]);
+                               continue;
+                       }
+                       printf("Changing group on %s\n", g.gl_pathv[i]);
+                       aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
+                       aa->gid = n_arg;
+                       do_setstat(in, out, g.gl_pathv[i], aa);
+               }
+               break;
+       case I_PWD:
+               printf("Remote working directory: %s\n", *pwd);
+               break;
+       case I_LPWD:
+               if (!getcwd(path_buf, sizeof(path_buf)))
+                       error("Couldn't get local cwd: %s",
+                           strerror(errno));
+               else
+                       printf("Local working directory: %s\n",
+                           path_buf);
+               break;
+       case I_QUIT:
+               return(-1);
+       case I_HELP:
+               help();
+               break;
+       case I_VERSION:
+               printf("SFTP protocol version %d\n", version);
+               break;
+       default:
+               fatal("%d is not implemented", cmdnum);
+       }
+
+       if (g.gl_pathc)
+               globfree(&g);
+       if (path1)
+               xfree(path1);
+       if (path2)
+               xfree(path2);
+
+       /* If an error occurs in batch mode we should abort. */
+       if (infile != stdin && err > 0)
+               return -1;
+
+       return(0);
+}
+
+void
+interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
+{
+       char *pwd;
+       char *dir = NULL;
+       char cmd[2048];
+
+       version = do_init(fd_in, fd_out);
+       if (version == -1)
+               fatal("Couldn't initialise connection to server");
+
+       pwd = do_realpath(fd_in, fd_out, ".");
+       if (pwd == NULL)
+               fatal("Need cwd");
+
+       if (file1 != NULL) {
+               dir = xstrdup(file1);
+               dir = make_absolute(dir, pwd);
+
+               if (remote_is_dir(fd_in, fd_out, dir) && file2 == NULL) {
+                       printf("Changing to: %s\n", dir);
+                       snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
+                       parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
+               } else {
+                       if (file2 == NULL)
+                               snprintf(cmd, sizeof cmd, "get %s", dir);
+                       else
+                               snprintf(cmd, sizeof cmd, "get %s %s", dir,
+                                   file2);
+
+                       parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
+                       return;
+               }
+       }
+#if HAVE_SETVBUF
+       setvbuf(stdout, NULL, _IOLBF, 0);
+       setvbuf(infile, NULL, _IOLBF, 0);
+#else
+       setlinebuf(stdout);
+       setlinebuf(infile);
+#endif
+
+       for(;;) {
+               char *cp;
+
+               printf("sftp> ");
+
+               /* XXX: use libedit */
+               if (fgets(cmd, sizeof(cmd), infile) == NULL) {
+                       printf("\n");
+                       break;
+               } else if (infile != stdin) /* Bluff typing */
+                       printf("%s", cmd);
+
+               cp = strrchr(cmd, '\n');
+               if (cp)
+                       *cp = '\0';
+
+               if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd))
+                       break;
+       }
+       xfree(pwd);
+}
diff --git a/openssh/sftp-int.h b/openssh/sftp-int.h
new file mode 100644 (file)
index 0000000..699e758
--- /dev/null
@@ -0,0 +1,27 @@
+/* $OpenBSD: sftp-int.h,v 1.4 2001/06/26 17:27:25 markus Exp $ */
+
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+void    interactive_loop(int, int, char *, char *);
diff --git a/openssh/sftp-server.8 b/openssh/sftp-server.8
new file mode 100644 (file)
index 0000000..0a0210a
--- /dev/null
@@ -0,0 +1,62 @@
+.\" $OpenBSD: sftp-server.8,v 1.8 2001/06/23 05:57:08 deraadt Exp $
+.\"
+.\" Copyright (c) 2000 Markus Friedl.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 30, 2000
+.Dt SFTP-SERVER 8
+.Os
+.Sh NAME
+.Nm sftp-server
+.Nd SFTP server subsystem
+.Sh SYNOPSIS
+.Nm sftp-server
+.Sh DESCRIPTION
+.Nm
+is a program that speaks the server side of SFTP protocol
+to stdout and expects client requests from stdin.
+.Nm
+is not intended to be called directly, but from
+.Xr sshd 8
+using the
+.Cm Subsystem
+option.
+See
+.Xr sshd 8
+for more information.
+.Sh SEE ALSO
+.Xr sftp 1 ,
+.Xr ssh 1 ,
+.Xr sshd 8
+.Rs
+.%A T. Ylonen
+.%A S. Lehtinen
+.%T "SSH File Transfer Protocol"
+.%N draft-ietf-secsh-filexfer-00.txt
+.%D January 2001
+.%O work in progress material
+.Re
+.Sh AUTHORS
+Markus Friedl <markus@openbsd.org>
+.Sh HISTORY
+.Nm
+first appeared in OpenBSD 2.8 .
diff --git a/openssh/sftp-server.c b/openssh/sftp-server.c
new file mode 100644 (file)
index 0000000..2ef9753
--- /dev/null
@@ -0,0 +1,1110 @@
+/*
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: sftp-server.c,v 1.30 2001/07/31 12:42:50 jakob Exp $");
+
+#include "buffer.h"
+#include "bufaux.h"
+#include "getput.h"
+#include "log.h"
+#include "xmalloc.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+
+/* helper */
+#define get_int64()                    buffer_get_int64(&iqueue);
+#define get_int()                      buffer_get_int(&iqueue);
+#define get_string(lenp)               buffer_get_string(&iqueue, lenp);
+#define TRACE                          debug
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+/* input and output queue */
+Buffer iqueue;
+Buffer oqueue;
+
+/* Version of client */
+int version;
+
+/* portable attibutes, etc. */
+
+typedef struct Stat Stat;
+
+struct Stat {
+       char *name;
+       char *long_name;
+       Attrib attrib;
+};
+
+static int
+errno_to_portable(int unixerrno)
+{
+       int ret = 0;
+
+       switch (unixerrno) {
+       case 0:
+               ret = SSH2_FX_OK;
+               break;
+       case ENOENT:
+       case ENOTDIR:
+       case EBADF:
+       case ELOOP:
+               ret = SSH2_FX_NO_SUCH_FILE;
+               break;
+       case EPERM:
+       case EACCES:
+       case EFAULT:
+               ret = SSH2_FX_PERMISSION_DENIED;
+               break;
+       case ENAMETOOLONG:
+       case EINVAL:
+               ret = SSH2_FX_BAD_MESSAGE;
+               break;
+       default:
+               ret = SSH2_FX_FAILURE;
+               break;
+       }
+       return ret;
+}
+
+static int
+flags_from_portable(int pflags)
+{
+       int flags = 0;
+
+       if ((pflags & SSH2_FXF_READ) &&
+           (pflags & SSH2_FXF_WRITE)) {
+               flags = O_RDWR;
+       } else if (pflags & SSH2_FXF_READ) {
+               flags = O_RDONLY;
+       } else if (pflags & SSH2_FXF_WRITE) {
+               flags = O_WRONLY;
+       }
+       if (pflags & SSH2_FXF_CREAT)
+               flags |= O_CREAT;
+       if (pflags & SSH2_FXF_TRUNC)
+               flags |= O_TRUNC;
+       if (pflags & SSH2_FXF_EXCL)
+               flags |= O_EXCL;
+       return flags;
+}
+
+static Attrib *
+get_attrib(void)
+{
+       return decode_attrib(&iqueue);
+}
+
+/* handle handles */
+
+typedef struct Handle Handle;
+struct Handle {
+       int use;
+       DIR *dirp;
+       int fd;
+       char *name;
+};
+
+enum {
+       HANDLE_UNUSED,
+       HANDLE_DIR,
+       HANDLE_FILE
+};
+
+Handle handles[100];
+
+static void
+handle_init(void)
+{
+       int i;
+
+       for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
+               handles[i].use = HANDLE_UNUSED;
+}
+
+static int
+handle_new(int use, char *name, int fd, DIR *dirp)
+{
+       int i;
+
+       for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
+               if (handles[i].use == HANDLE_UNUSED) {
+                       handles[i].use = use;
+                       handles[i].dirp = dirp;
+                       handles[i].fd = fd;
+                       handles[i].name = name;
+                       return i;
+               }
+       }
+       return -1;
+}
+
+static int
+handle_is_ok(int i, int type)
+{
+       return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
+           handles[i].use == type;
+}
+
+static int
+handle_to_string(int handle, char **stringp, int *hlenp)
+{
+       if (stringp == NULL || hlenp == NULL)
+               return -1;
+       *stringp = xmalloc(sizeof(int32_t));
+       PUT_32BIT(*stringp, handle);
+       *hlenp = sizeof(int32_t);
+       return 0;
+}
+
+static int
+handle_from_string(char *handle, u_int hlen)
+{
+       int val;
+
+       if (hlen != sizeof(int32_t))
+               return -1;
+       val = GET_32BIT(handle);
+       if (handle_is_ok(val, HANDLE_FILE) ||
+           handle_is_ok(val, HANDLE_DIR))
+               return val;
+       return -1;
+}
+
+static char *
+handle_to_name(int handle)
+{
+       if (handle_is_ok(handle, HANDLE_DIR)||
+           handle_is_ok(handle, HANDLE_FILE))
+               return handles[handle].name;
+       return NULL;
+}
+
+static DIR *
+handle_to_dir(int handle)
+{
+       if (handle_is_ok(handle, HANDLE_DIR))
+               return handles[handle].dirp;
+       return NULL;
+}
+
+static int
+handle_to_fd(int handle)
+{
+       if (handle_is_ok(handle, HANDLE_FILE))
+               return handles[handle].fd;
+       return -1;
+}
+
+static int
+handle_close(int handle)
+{
+       int ret = -1;
+
+       if (handle_is_ok(handle, HANDLE_FILE)) {
+               ret = close(handles[handle].fd);
+               handles[handle].use = HANDLE_UNUSED;
+       } else if (handle_is_ok(handle, HANDLE_DIR)) {
+               ret = closedir(handles[handle].dirp);
+               handles[handle].use = HANDLE_UNUSED;
+       } else {
+               errno = ENOENT;
+       }
+       return ret;
+}
+
+static int
+get_handle(void)
+{
+       char *handle;
+       int val = -1;
+       u_int hlen;
+
+       handle = get_string(&hlen);
+       if (hlen < 256)
+               val = handle_from_string(handle, hlen);
+       xfree(handle);
+       return val;
+}
+
+/* send replies */
+
+static void
+send_msg(Buffer *m)
+{
+       int mlen = buffer_len(m);
+
+       buffer_put_int(&oqueue, mlen);
+       buffer_append(&oqueue, buffer_ptr(m), mlen);
+       buffer_consume(m, mlen);
+}
+
+static void
+send_status(u_int32_t id, u_int32_t error)
+{
+       Buffer msg;
+       const char *status_messages[] = {
+               "Success",                      /* SSH_FX_OK */
+               "End of file",                  /* SSH_FX_EOF */
+               "No such file",                 /* SSH_FX_NO_SUCH_FILE */
+               "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
+               "Failure",                      /* SSH_FX_FAILURE */
+               "Bad message",                  /* SSH_FX_BAD_MESSAGE */
+               "No connection",                /* SSH_FX_NO_CONNECTION */
+               "Connection lost",              /* SSH_FX_CONNECTION_LOST */
+               "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
+               "Unknown error"                 /* Others */
+       };
+
+       TRACE("sent status id %d error %d", id, error);
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_STATUS);
+       buffer_put_int(&msg, id);
+       buffer_put_int(&msg, error);
+       if (version >= 3) {
+               buffer_put_cstring(&msg,
+                   status_messages[MIN(error,SSH2_FX_MAX)]);
+               buffer_put_cstring(&msg, "");
+       }
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+static void
+send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
+{
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, type);
+       buffer_put_int(&msg, id);
+       buffer_put_string(&msg, data, dlen);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+static void
+send_data(u_int32_t id, char *data, int dlen)
+{
+       TRACE("sent data id %d len %d", id, dlen);
+       send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
+}
+
+static void
+send_handle(u_int32_t id, int handle)
+{
+       char *string;
+       int hlen;
+
+       handle_to_string(handle, &string, &hlen);
+       TRACE("sent handle id %d handle %d", id, handle);
+       send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
+       xfree(string);
+}
+
+static void
+send_names(u_int32_t id, int count, Stat *stats)
+{
+       Buffer msg;
+       int i;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_NAME);
+       buffer_put_int(&msg, id);
+       buffer_put_int(&msg, count);
+       TRACE("sent names id %d count %d", id, count);
+       for (i = 0; i < count; i++) {
+               buffer_put_cstring(&msg, stats[i].name);
+               buffer_put_cstring(&msg, stats[i].long_name);
+               encode_attrib(&msg, &stats[i].attrib);
+       }
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+static void
+send_attrib(u_int32_t id, Attrib *a)
+{
+       Buffer msg;
+
+       TRACE("sent attrib id %d have 0x%x", id, a->flags);
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_ATTRS);
+       buffer_put_int(&msg, id);
+       encode_attrib(&msg, a);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+/* parse incoming */
+
+static void
+process_init(void)
+{
+       Buffer msg;
+
+       version = buffer_get_int(&iqueue);
+       TRACE("client version %d", version);
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_VERSION);
+       buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+static void
+process_open(void)
+{
+       u_int32_t id, pflags;
+       Attrib *a;
+       char *name;
+       int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       name = get_string(NULL);
+       pflags = get_int();             /* portable flags */
+       a = get_attrib();
+       flags = flags_from_portable(pflags);
+       mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
+       TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
+       fd = open(name, flags, mode);
+       if (fd < 0) {
+               status = errno_to_portable(errno);
+       } else {
+               handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);
+               if (handle < 0) {
+                       close(fd);
+               } else {
+                       send_handle(id, handle);
+                       status = SSH2_FX_OK;
+               }
+       }
+       if (status != SSH2_FX_OK)
+               send_status(id, status);
+       xfree(name);
+}
+
+static void
+process_close(void)
+{
+       u_int32_t id;
+       int handle, ret, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       handle = get_handle();
+       TRACE("close id %d handle %d", id, handle);
+       ret = handle_close(handle);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       send_status(id, status);
+}
+
+static void
+process_read(void)
+{
+       char buf[64*1024];
+       u_int32_t id, len;
+       int handle, fd, ret, status = SSH2_FX_FAILURE;
+       u_int64_t off;
+
+       id = get_int();
+       handle = get_handle();
+       off = get_int64();
+       len = get_int();
+
+       TRACE("read id %d handle %d off %llu len %d", id, handle,
+           (u_int64_t)off, len);
+       if (len > sizeof buf) {
+               len = sizeof buf;
+               log("read change len %d", len);
+       }
+       fd = handle_to_fd(handle);
+       if (fd >= 0) {
+               if (lseek(fd, off, SEEK_SET) < 0) {
+                       error("process_read: seek failed");
+                       status = errno_to_portable(errno);
+               } else {
+                       ret = read(fd, buf, len);
+                       if (ret < 0) {
+                               status = errno_to_portable(errno);
+                       } else if (ret == 0) {
+                               status = SSH2_FX_EOF;
+                       } else {
+                               send_data(id, buf, ret);
+                               status = SSH2_FX_OK;
+                       }
+               }
+       }
+       if (status != SSH2_FX_OK)
+               send_status(id, status);
+}
+
+static void
+process_write(void)
+{
+       u_int32_t id;
+       u_int64_t off;
+       u_int len;
+       int handle, fd, ret, status = SSH2_FX_FAILURE;
+       char *data;
+
+       id = get_int();
+       handle = get_handle();
+       off = get_int64();
+       data = get_string(&len);
+
+       TRACE("write id %d handle %d off %llu len %d", id, handle,
+           (u_int64_t)off, len);
+       fd = handle_to_fd(handle);
+       if (fd >= 0) {
+               if (lseek(fd, off, SEEK_SET) < 0) {
+                       status = errno_to_portable(errno);
+                       error("process_write: seek failed");
+               } else {
+/* XXX ATOMICIO ? */
+                       ret = write(fd, data, len);
+                       if (ret == -1) {
+                               error("process_write: write failed");
+                               status = errno_to_portable(errno);
+                       } else if (ret == len) {
+                               status = SSH2_FX_OK;
+                       } else {
+                               log("nothing at all written");
+                       }
+               }
+       }
+       send_status(id, status);
+       xfree(data);
+}
+
+static void
+process_do_stat(int do_lstat)
+{
+       Attrib a;
+       struct stat st;
+       u_int32_t id;
+       char *name;
+       int ret, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       name = get_string(NULL);
+       TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
+       ret = do_lstat ? lstat(name, &st) : stat(name, &st);
+       if (ret < 0) {
+               status = errno_to_portable(errno);
+       } else {
+               stat_to_attrib(&st, &a);
+               send_attrib(id, &a);
+               status = SSH2_FX_OK;
+       }
+       if (status != SSH2_FX_OK)
+               send_status(id, status);
+       xfree(name);
+}
+
+static void
+process_stat(void)
+{
+       process_do_stat(0);
+}
+
+static void
+process_lstat(void)
+{
+       process_do_stat(1);
+}
+
+static void
+process_fstat(void)
+{
+       Attrib a;
+       struct stat st;
+       u_int32_t id;
+       int fd, ret, handle, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       handle = get_handle();
+       TRACE("fstat id %d handle %d", id, handle);
+       fd = handle_to_fd(handle);
+       if (fd  >= 0) {
+               ret = fstat(fd, &st);
+               if (ret < 0) {
+                       status = errno_to_portable(errno);
+               } else {
+                       stat_to_attrib(&st, &a);
+                       send_attrib(id, &a);
+                       status = SSH2_FX_OK;
+               }
+       }
+       if (status != SSH2_FX_OK)
+               send_status(id, status);
+}
+
+static struct timeval *
+attrib_to_tv(Attrib *a)
+{
+       static struct timeval tv[2];
+
+       tv[0].tv_sec = a->atime;
+       tv[0].tv_usec = 0;
+       tv[1].tv_sec = a->mtime;
+       tv[1].tv_usec = 0;
+       return tv;
+}
+
+static void
+process_setstat(void)
+{
+       Attrib *a;
+       u_int32_t id;
+       char *name;
+       int ret;
+       int status = SSH2_FX_OK;
+
+       id = get_int();
+       name = get_string(NULL);
+       a = get_attrib();
+       TRACE("setstat id %d name %s", id, name);
+       if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
+               ret = chmod(name, a->perm & 0777);
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+               ret = utimes(name, attrib_to_tv(a));
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+               ret = chown(name, a->uid, a->gid);
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       send_status(id, status);
+       xfree(name);
+}
+
+static void
+process_fsetstat(void)
+{
+       Attrib *a;
+       u_int32_t id;
+       int handle, fd, ret;
+       int status = SSH2_FX_OK;
+       char *name;
+
+       id = get_int();
+       handle = get_handle();
+       a = get_attrib();
+       TRACE("fsetstat id %d handle %d", id, handle);
+       fd = handle_to_fd(handle);
+       name = handle_to_name(handle);
+       if (fd < 0 || name == NULL) {
+               status = SSH2_FX_FAILURE;
+       } else {
+               if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
+#ifdef HAVE_FCHMOD
+                       ret = fchmod(fd, a->perm & 0777);
+#else
+                       ret = chmod(name, a->perm & 0777);
+#endif
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+               if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+#ifdef HAVE_FUTIMES
+                       ret = futimes(fd, attrib_to_tv(a));
+#else
+                       ret = utimes(name, attrib_to_tv(a));
+#endif
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+               if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+#ifdef HAVE_FCHOWN
+                       ret = fchown(fd, a->uid, a->gid);
+#else
+                       ret = chown(name, a->uid, a->gid);
+#endif
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+       }
+       send_status(id, status);
+}
+
+static void
+process_opendir(void)
+{
+       DIR *dirp = NULL;
+       char *path;
+       int handle, status = SSH2_FX_FAILURE;
+       u_int32_t id;
+
+       id = get_int();
+       path = get_string(NULL);
+       TRACE("opendir id %d path %s", id, path);
+       dirp = opendir(path);
+       if (dirp == NULL) {
+               status = errno_to_portable(errno);
+       } else {
+               handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp);
+               if (handle < 0) {
+                       closedir(dirp);
+               } else {
+                       send_handle(id, handle);
+                       status = SSH2_FX_OK;
+               }
+
+       }
+       if (status != SSH2_FX_OK)
+               send_status(id, status);
+       xfree(path);
+}
+
+/*
+ * drwxr-xr-x    5 markus   markus       1024 Jan 13 18:39 .ssh
+ */
+static char *
+ls_file(char *name, struct stat *st)
+{
+       int ulen, glen, sz = 0;
+       struct passwd *pw;
+       struct group *gr;
+       struct tm *ltime = localtime(&st->st_mtime);
+       char *user, *group;
+       char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
+
+       strmode(st->st_mode, mode);
+       if ((pw = getpwuid(st->st_uid)) != NULL) {
+               user = pw->pw_name;
+       } else {
+               snprintf(ubuf, sizeof ubuf, "%d", st->st_uid);
+               user = ubuf;
+       }
+       if ((gr = getgrgid(st->st_gid)) != NULL) {
+               group = gr->gr_name;
+       } else {
+               snprintf(gbuf, sizeof gbuf, "%d", st->st_gid);
+               group = gbuf;
+       }
+       if (ltime != NULL) {
+               if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
+                       sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
+               else
+                       sz = strftime(tbuf, sizeof tbuf, "%b %e  %Y", ltime);
+       }
+       if (sz == 0)
+               tbuf[0] = '\0';
+       ulen = MAX(strlen(user), 8);
+       glen = MAX(strlen(group), 8);
+       snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode,
+           st->st_nlink, ulen, user, glen, group,
+           (u_int64_t)st->st_size, tbuf, name);
+       return xstrdup(buf);
+}
+
+static void
+process_readdir(void)
+{
+       DIR *dirp;
+       struct dirent *dp;
+       char *path;
+       int handle;
+       u_int32_t id;
+
+       id = get_int();
+       handle = get_handle();
+       TRACE("readdir id %d handle %d", id, handle);
+       dirp = handle_to_dir(handle);
+       path = handle_to_name(handle);
+       if (dirp == NULL || path == NULL) {
+               send_status(id, SSH2_FX_FAILURE);
+       } else {
+               struct stat st;
+               char pathname[1024];
+               Stat *stats;
+               int nstats = 10, count = 0, i;
+               stats = xmalloc(nstats * sizeof(Stat));
+               while ((dp = readdir(dirp)) != NULL) {
+                       if (count >= nstats) {
+                               nstats *= 2;
+                               stats = xrealloc(stats, nstats * sizeof(Stat));
+                       }
+/* XXX OVERFLOW ? */
+                       snprintf(pathname, sizeof pathname, "%s%s%s", path,
+                           strcmp(path, "/") ? "/" : "", dp->d_name);
+                       if (lstat(pathname, &st) < 0)
+                               continue;
+                       stat_to_attrib(&st, &(stats[count].attrib));
+                       stats[count].name = xstrdup(dp->d_name);
+                       stats[count].long_name = ls_file(dp->d_name, &st);
+                       count++;
+                       /* send up to 100 entries in one message */
+                       /* XXX check packet size instead */
+                       if (count == 100)
+                               break;
+               }
+               if (count > 0) {
+                       send_names(id, count, stats);
+                       for(i = 0; i < count; i++) {
+                               xfree(stats[i].name);
+                               xfree(stats[i].long_name);
+                       }
+               } else {
+                       send_status(id, SSH2_FX_EOF);
+               }
+               xfree(stats);
+       }
+}
+
+static void
+process_remove(void)
+{
+       char *name;
+       u_int32_t id;
+       int status = SSH2_FX_FAILURE;
+       int ret;
+
+       id = get_int();
+       name = get_string(NULL);
+       TRACE("remove id %d name %s", id, name);
+       ret = unlink(name);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       send_status(id, status);
+       xfree(name);
+}
+
+static void
+process_mkdir(void)
+{
+       Attrib *a;
+       u_int32_t id;
+       char *name;
+       int ret, mode, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       name = get_string(NULL);
+       a = get_attrib();
+       mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
+           a->perm & 0777 : 0777;
+       TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
+       ret = mkdir(name, mode);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       send_status(id, status);
+       xfree(name);
+}
+
+static void
+process_rmdir(void)
+{
+       u_int32_t id;
+       char *name;
+       int ret, status;
+
+       id = get_int();
+       name = get_string(NULL);
+       TRACE("rmdir id %d name %s", id, name);
+       ret = rmdir(name);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       send_status(id, status);
+       xfree(name);
+}
+
+static void
+process_realpath(void)
+{
+       char resolvedname[MAXPATHLEN];
+       u_int32_t id;
+       char *path;
+
+       id = get_int();
+       path = get_string(NULL);
+       if (path[0] == '\0') {
+               xfree(path);
+               path = xstrdup(".");
+       }
+       TRACE("realpath id %d path %s", id, path);
+       if (realpath(path, resolvedname) == NULL) {
+               send_status(id, errno_to_portable(errno));
+       } else {
+               Stat s;
+               attrib_clear(&s.attrib);
+               s.name = s.long_name = resolvedname;
+               send_names(id, 1, &s);
+       }
+       xfree(path);
+}
+
+static void
+process_rename(void)
+{
+       u_int32_t id;
+       struct stat st;
+       char *oldpath, *newpath;
+       int ret, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       TRACE("rename id %d old %s new %s", id, oldpath, newpath);
+       /* fail if 'newpath' exists */
+       if (stat(newpath, &st) == -1) {
+               ret = rename(oldpath, newpath);
+               status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       }
+       send_status(id, status);
+       xfree(oldpath);
+       xfree(newpath);
+}
+
+static void
+process_readlink(void)
+{
+       u_int32_t id;
+       int len;
+       char link[MAXPATHLEN];
+       char *path;
+
+       id = get_int();
+       path = get_string(NULL);
+       TRACE("readlink id %d path %s", id, path);
+       if ((len = readlink(path, link, sizeof(link) - 1)) == -1)
+               send_status(id, errno_to_portable(errno));
+       else {
+               Stat s;
+               
+               link[len] = '\0';
+               attrib_clear(&s.attrib);
+               s.name = s.long_name = link;
+               send_names(id, 1, &s);
+       }
+       xfree(path);
+}
+
+static void
+process_symlink(void)
+{
+       u_int32_t id;
+       struct stat st;
+       char *oldpath, *newpath;
+       int ret, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
+       /* fail if 'newpath' exists */
+       if (stat(newpath, &st) == -1) {
+               ret = symlink(oldpath, newpath);
+               status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       }
+       send_status(id, status);
+       xfree(oldpath);
+       xfree(newpath);
+}
+
+static void
+process_extended(void)
+{
+       u_int32_t id;
+       char *request;
+
+       id = get_int();
+       request = get_string(NULL);
+       send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */
+       xfree(request);
+}
+
+/* stolen from ssh-agent */
+
+static void
+process(void)
+{
+       u_int msg_len;
+       u_int type;
+       u_char *cp;
+
+       if (buffer_len(&iqueue) < 5)
+               return;         /* Incomplete message. */
+       cp = (u_char *) buffer_ptr(&iqueue);
+       msg_len = GET_32BIT(cp);
+       if (msg_len > 256 * 1024) {
+               error("bad message ");
+               exit(11);
+       }
+       if (buffer_len(&iqueue) < msg_len + 4)
+               return;
+       buffer_consume(&iqueue, 4);
+       type = buffer_get_char(&iqueue);
+       switch (type) {
+       case SSH2_FXP_INIT:
+               process_init();
+               break;
+       case SSH2_FXP_OPEN:
+               process_open();
+               break;
+       case SSH2_FXP_CLOSE:
+               process_close();
+               break;
+       case SSH2_FXP_READ:
+               process_read();
+               break;
+       case SSH2_FXP_WRITE:
+               process_write();
+               break;
+       case SSH2_FXP_LSTAT:
+               process_lstat();
+               break;
+       case SSH2_FXP_FSTAT:
+               process_fstat();
+               break;
+       case SSH2_FXP_SETSTAT:
+               process_setstat();
+               break;
+       case SSH2_FXP_FSETSTAT:
+               process_fsetstat();
+               break;
+       case SSH2_FXP_OPENDIR:
+               process_opendir();
+               break;
+       case SSH2_FXP_READDIR:
+               process_readdir();
+               break;
+       case SSH2_FXP_REMOVE:
+               process_remove();
+               break;
+       case SSH2_FXP_MKDIR:
+               process_mkdir();
+               break;
+       case SSH2_FXP_RMDIR:
+               process_rmdir();
+               break;
+       case SSH2_FXP_REALPATH:
+               process_realpath();
+               break;
+       case SSH2_FXP_STAT:
+               process_stat();
+               break;
+       case SSH2_FXP_RENAME:
+               process_rename();
+               break;
+       case SSH2_FXP_READLINK:
+               process_readlink();
+               break;
+       case SSH2_FXP_SYMLINK:
+               process_symlink();
+               break;
+       case SSH2_FXP_EXTENDED:
+               process_extended();
+               break;
+       default:
+               error("Unknown message %d", type);
+               break;
+       }
+}
+
+int
+main(int ac, char **av)
+{
+       fd_set *rset, *wset;
+       int in, out, max;
+       ssize_t len, olen, set_size;
+
+       /* XXX should use getopt */
+
+       __progname = get_progname(av[0]);
+       handle_init();
+
+#ifdef DEBUG_SFTP_SERVER
+       log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
+#endif
+
+       in = dup(STDIN_FILENO);
+       out = dup(STDOUT_FILENO);
+
+#ifdef HAVE_CYGWIN
+       setmode(in, O_BINARY);
+       setmode(out, O_BINARY);
+#endif
+
+       max = 0;
+       if (in > max)
+               max = in;
+       if (out > max)
+               max = out;
+
+       buffer_init(&iqueue);
+       buffer_init(&oqueue);
+
+       set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
+       rset = (fd_set *)xmalloc(set_size);
+       wset = (fd_set *)xmalloc(set_size);
+
+       for (;;) {
+               memset(rset, 0, set_size);
+               memset(wset, 0, set_size);
+
+               FD_SET(in, rset);
+               olen = buffer_len(&oqueue);
+               if (olen > 0)
+                       FD_SET(out, wset);
+
+               if (select(max+1, rset, wset, NULL, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       exit(2);
+               }
+
+               /* copy stdin to iqueue */
+               if (FD_ISSET(in, rset)) {
+                       char buf[4*4096];
+                       len = read(in, buf, sizeof buf);
+                       if (len == 0) {
+                               debug("read eof");
+                               exit(0);
+                       } else if (len < 0) {
+                               error("read error");
+                               exit(1);
+                       } else {
+                               buffer_append(&iqueue, buf, len);
+                       }
+               }
+               /* send oqueue to stdout */
+               if (FD_ISSET(out, wset)) {
+                       len = write(out, buffer_ptr(&oqueue), olen);
+                       if (len < 0) {
+                               error("write error");
+                               exit(1);
+                       } else {
+                               buffer_consume(&oqueue, len);
+                       }
+               }
+               /* process requests from client */
+               process();
+       }
+}
diff --git a/openssh/sftp.1 b/openssh/sftp.1
new file mode 100644 (file)
index 0000000..0cc4e2b
--- /dev/null
@@ -0,0 +1,256 @@
+.\" $OpenBSD: sftp.1,v 1.26 2001/09/17 20:38:09 stevesk Exp $
+.\"
+.\" Copyright (c) 2001 Damien Miller.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd February 4, 2001
+.Dt SFTP 1
+.Os
+.Sh NAME
+.Nm sftp
+.Nd Secure file transfer program
+.Sh SYNOPSIS
+.Nm sftp
+.Op Fl 1Cv
+.Op Fl b Ar batchfile
+.Op Fl F Ar ssh_config
+.Op Fl o Ar ssh_option
+.Op Fl s Ar subsystem | sftp_server
+.Op Fl S Ar program
+.Ar host
+.Nm sftp
+.Op [\fIuser\fR@]\fIhost\fR[:\fIfile\fR [\fIfile\fR]]
+.Nm sftp
+.Op [\fIuser\fR@]\fIhost\fR[:\fIdir\fR[\fI/\fR]]
+.Sh DESCRIPTION
+.Nm
+is an interactive file transfer program, similar to
+.Xr ftp 1 ,
+which performs all operations over an encrypted
+.Xr ssh 1
+transport.
+It may also use many features of ssh, such as public key authentication and
+compression.
+.Nm
+connects and logs into the specified
+.Ar host ,
+then enters an interactive command mode.
+.Pp
+The second usage format will retrieve files automatically if a non-interactive
+authentication method is used; otherwise it will do so after
+successful interactive authentication.
+.Pp
+The last usage format allows the sftp client to start in a remote directory.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 1
+Specify the use of protocol version 1.
+.It Fl b Ar batchfile
+Batch mode reads a series of commands from an input
+.Ar batchfile
+instead of
+.Em stdin .
+Since it lacks user interaction it should be used in conjunction with
+non-interactive authentication.
+.Nm
+will abort if any of the following
+commands fail:
+.Ic get , put , rename , ln , rm , mkdir , chdir , lchdir
+and
+.Ic lmkdir .
+.It Fl C
+Enables compression (via ssh's
+.Fl C
+flag).
+.It Fl F Ar ssh_config
+Specifies an alternative
+per-user configuration file for
+.Nm ssh .
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl o Ar ssh_option
+Can be used to pass options to
+.Nm ssh
+in the format used in the
+.Xr ssh 1
+configuration file. This is useful for specifying options
+for which there is no separate
+.Nm sftp
+command-line flag.  For example, to specify an alternate
+port use:
+.Ic sftp -oPort=24 .
+.It Fl s Ar subsystem | sftp_server
+Specifies the SSH2 subsystem or the path for an sftp server
+on the remote host.  A path is useful for using sftp over
+protocol version 1, or when the remote
+.Nm sshd
+does not have an sftp subsystem configured.
+.It Fl S Ar program
+Name of the
+.Ar program
+to use for the encrypted connection.
+The program must understand
+.Xr ssh 1
+options.
+.It Fl v
+Raise logging level. This option is also passed to ssh.
+.El
+.Sh INTERACTIVE COMMANDS
+Once in interactive mode,
+.Nm
+understands a set of commands similar to those of
+.Xr ftp 1 .
+Commands are case insensitive and pathnames may be enclosed in quotes if they
+contain spaces.
+.Bl -tag -width Ds
+.It Ic bye
+Quit sftp.
+.It Ic cd Ar path
+Change remote directory to
+.Ar path .
+.It Ic lcd Ar path
+Change local directory to
+.Ar path .
+.It Ic chgrp Ar grp Ar path
+Change group of file
+.Ar path
+to
+.Ar grp .
+.Ar grp
+must be a numeric GID.
+.It Ic chmod Ar mode Ar path
+Change permissions of file
+.Ar path
+to
+.Ar mode .
+.It Ic chown Ar own Ar path
+Change owner of file
+.Ar path
+to
+.Ar own .
+.Ar own
+must be a numeric UID.
+.It Ic exit
+Quit sftp.
+.It Xo Ic get
+.Op Ar flags
+.Ar remote-path
+.Op Ar local-path
+.Xc
+Retrieve the
+.Ar remote-path
+and store it on the local machine.
+If the local
+path name is not specified, it is given the same name it has on the
+remote machine. If the
+.Fl P
+flag is specified, then the file's full permission and access time are
+copied too.
+.It Ic help
+Display help text.
+.It Ic lls Op Ar ls-options Op Ar path
+Display local directory listing of either
+.Ar path
+or current directory if
+.Ar path
+is not specified.
+.It Ic lmkdir Ar path
+Create local directory specified by
+.Ar path .
+.It Ic ln Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic lpwd
+Print local working directory.
+.It Ic ls Op Ar path
+Display remote directory listing of either
+.Ar path
+or current directory if
+.Ar path
+is not specified.
+.It Ic lumask Ar umask
+Set local umask to
+.Ar umask .
+.It Ic mkdir Ar path
+Create remote directory specified by
+.Ar path .
+.It Xo Ic put
+.Op Ar flags
+.Ar local-path
+.Op Ar local-path
+.Xc
+Upload
+.Ar local-path
+and store it on the remote machine. If the remote path name is not
+specified, it is given the same name it has on the local machine. If the
+.Fl P
+flag is specified, then the file's full permission and access time are
+copied too.
+.It Ic pwd
+Display remote working directory.
+.It Ic quit
+Quit sftp.
+.It Ic rename Ar oldpath Ar newpath
+Rename remote file from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic rmdir Ar path
+Remove remote directory specified by
+.Ar path .
+.It Ic rm Ar path
+Delete remote file specified by
+.Ar path .
+.It Ic symlink Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic ! Ar command
+Execute
+.Ar command
+in local shell.
+.It Ic !
+Escape to local shell.
+.It Ic ?
+Synonym for help.
+.El
+.Sh AUTHORS
+Damien Miller <djm@mindrot.org>
+.Sh SEE ALSO
+.Xr scp 1 ,
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sftp-server 8 ,
+.Xr sshd 8
+.Rs
+.%A T. Ylonen
+.%A S. Lehtinen
+.%T "SSH File Transfer Protocol"
+.%N draft-ietf-secsh-filexfer-00.txt
+.%D January 2001
+.%O work in progress material
+.Re
diff --git a/openssh/sftp.c b/openssh/sftp.c
new file mode 100644 (file)
index 0000000..06110f9
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2001 Damien Miller.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+RCSID("$OpenBSD: sftp.c,v 1.21 2001/09/19 19:24:19 stevesk Exp $");
+
+/* XXX: commandline mode */
+/* XXX: short-form remote directory listings (like 'ls -C') */
+
+#include "buffer.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "pathnames.h"
+#include "misc.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+#include "sftp-client.h"
+#include "sftp-int.h"
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+char *ssh_program = _PATH_SSH_PROGRAM;
+FILE* infile;
+
+static void
+connect_to_server(char **args, int *in, int *out, pid_t *sshpid)
+{
+       int c_in, c_out;
+#ifdef USE_PIPES
+       int pin[2], pout[2];
+       if ((pipe(pin) == -1) || (pipe(pout) == -1))
+               fatal("pipe: %s", strerror(errno));
+       *in = pin[0];
+       *out = pout[1];
+       c_in = pout[0];
+       c_out = pin[1];
+#else /* USE_PIPES */
+       int inout[2];
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
+               fatal("socketpair: %s", strerror(errno));
+       *in = *out = inout[0];
+       c_in = c_out = inout[1];
+#endif /* USE_PIPES */
+
+       if ((*sshpid = fork()) == -1)
+               fatal("fork: %s", strerror(errno));
+       else if (*sshpid == 0) {
+               if ((dup2(c_in, STDIN_FILENO) == -1) ||
+                   (dup2(c_out, STDOUT_FILENO) == -1)) {
+                       fprintf(stderr, "dup2: %s\n", strerror(errno));
+                       exit(1);
+               }
+               close(*in);
+               close(*out);
+               close(c_in);
+               close(c_out);
+               execv(ssh_program, args);
+               fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno));
+               exit(1);
+       }
+
+       close(c_in);
+       close(c_out);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+           "usage: sftp [-1Cv] [-b batchfile] [-F config] [-o option] [-s subsystem|path]\n"
+           "            [-S program] [user@]host[:file [file]]\n");
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int in, out, ch;
+       pid_t sshpid;
+       char *host, *userhost, *cp, *file2;
+       int debug_level = 0, sshver = 2;
+       char *file1 = NULL, *sftp_server = NULL;
+       LogLevel ll = SYSLOG_LEVEL_INFO;
+       arglist args;
+       extern int optind;
+       extern char *optarg;
+
+       __progname = get_progname(argv[0]);
+       args.list = NULL;
+       addargs(&args, "ssh");         /* overwritten with ssh_program */
+       addargs(&args, "-oFallBackToRsh no");
+       addargs(&args, "-oForwardX11 no");
+       addargs(&args, "-oForwardAgent no");
+       addargs(&args, "-oClearAllForwardings yes");
+       ll = SYSLOG_LEVEL_INFO;
+       infile = stdin;         /* Read from STDIN unless changed by -b */
+
+       while ((ch = getopt(argc, argv, "1hvCo:s:S:b:F:")) != -1) {
+               switch (ch) {
+               case 'C':
+                       addargs(&args, "-C");
+                       break;
+               case 'v':
+                       if (debug_level < 3) {
+                               addargs(&args, "-v");
+                               ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
+                       }
+                       debug_level++;
+                       break;
+               case 'F':
+               case 'o':
+                       addargs(&args, "-%c%s", ch, optarg);
+                       break;
+               case '1':
+                       sshver = 1;
+                       if (sftp_server == NULL)
+                               sftp_server = _PATH_SFTP_SERVER;
+                       break;
+               case 's':
+                       sftp_server = optarg;
+                       break;
+               case 'S':
+                       ssh_program = optarg;
+                       break;
+               case 'b':
+                       if (infile == stdin) {
+                               infile = fopen(optarg, "r");
+                               if (infile == NULL)
+                                       fatal("%s (%s).", strerror(errno), optarg);
+                       } else
+                               fatal("Filename already specified.");
+                       break;
+               case 'h':
+               default:
+                       usage();
+               }
+       }
+
+       if (optind == argc || argc > (optind + 2))
+               usage();
+
+       userhost = xstrdup(argv[optind]);
+       file2 = argv[optind+1];
+
+       if ((cp = colon(userhost)) != NULL) {
+               *cp++ = '\0';
+               file1 = cp;
+       }
+
+       if ((host = strchr(userhost, '@')) == NULL)
+               host = userhost;
+       else {
+               *host++ = '\0';
+               if (!userhost[0]) {
+                       fprintf(stderr, "Missing username\n");
+                       usage();
+               }
+               addargs(&args, "-l%s",userhost);
+       }
+
+       host = cleanhostname(host);
+       if (!*host) {
+               fprintf(stderr, "Missing hostname\n");
+               usage();
+       }
+
+       log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
+       addargs(&args, "-oProtocol %d", sshver);
+
+       /* no subsystem if the server-spec contains a '/' */
+       if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 
+               addargs(&args, "-s");
+
+       addargs(&args, "%s", host);
+       addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp"));
+       args.list[0] = ssh_program;
+
+       fprintf(stderr, "Connecting to %s...\n", host);
+
+       connect_to_server(args.list, &in, &out, &sshpid);
+
+       interactive_loop(in, out, file1, file2);
+
+#if !defined(USE_PIPES)
+        shutdown(in, SHUT_RDWR);
+        shutdown(out, SHUT_RDWR);
+#endif
+
+       close(in);
+       close(out);
+       if (infile != stdin)
+               fclose(infile);
+
+       if (waitpid(sshpid, NULL, 0) == -1)
+               fatal("Couldn't wait for ssh process: %s", strerror(errno));
+
+       exit(0);
+}
diff --git a/openssh/sftp.h b/openssh/sftp.h
new file mode 100644 (file)
index 0000000..2ad9586
--- /dev/null
@@ -0,0 +1,91 @@
+/*     $OpenBSD: sftp.h,v 1.3 2001/03/07 10:11:23 djm Exp $    */
+
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * draft-ietf-secsh-filexfer-01.txt
+ */
+
+/* version */
+#define        SSH2_FILEXFER_VERSION           3
+
+/* client to server */
+#define SSH2_FXP_INIT                  1
+#define SSH2_FXP_OPEN                  3
+#define SSH2_FXP_CLOSE                 4
+#define SSH2_FXP_READ                  5
+#define SSH2_FXP_WRITE                 6
+#define SSH2_FXP_LSTAT                 7
+#define SSH2_FXP_FSTAT                 8
+#define SSH2_FXP_SETSTAT               9
+#define SSH2_FXP_FSETSTAT              10
+#define SSH2_FXP_OPENDIR               11
+#define SSH2_FXP_READDIR               12
+#define SSH2_FXP_REMOVE                        13
+#define SSH2_FXP_MKDIR                 14
+#define SSH2_FXP_RMDIR                 15
+#define SSH2_FXP_REALPATH              16
+#define SSH2_FXP_STAT                  17
+#define SSH2_FXP_RENAME                        18
+#define SSH2_FXP_READLINK              19
+#define SSH2_FXP_SYMLINK               20
+
+/* server to client */
+#define SSH2_FXP_VERSION               2
+#define SSH2_FXP_STATUS                        101
+#define SSH2_FXP_HANDLE                        102
+#define SSH2_FXP_DATA                  103
+#define SSH2_FXP_NAME                  104
+#define SSH2_FXP_ATTRS                 105
+
+#define SSH2_FXP_EXTENDED              200
+#define SSH2_FXP_EXTENDED_REPLY                201
+
+/* attributes */
+#define SSH2_FILEXFER_ATTR_SIZE                0x00000001
+#define SSH2_FILEXFER_ATTR_UIDGID      0x00000002
+#define SSH2_FILEXFER_ATTR_PERMISSIONS 0x00000004
+#define SSH2_FILEXFER_ATTR_ACMODTIME   0x00000008
+#define SSH2_FILEXFER_ATTR_EXTENDED    0x80000000
+
+/* portable open modes */
+#define SSH2_FXF_READ                  0x00000001
+#define SSH2_FXF_WRITE                 0x00000002
+#define SSH2_FXF_APPEND                        0x00000004
+#define SSH2_FXF_CREAT                 0x00000008
+#define SSH2_FXF_TRUNC                 0x00000010
+#define SSH2_FXF_EXCL                  0x00000020
+
+/* status messages */
+#define SSH2_FX_OK                     0
+#define SSH2_FX_EOF                    1
+#define SSH2_FX_NO_SUCH_FILE           2
+#define SSH2_FX_PERMISSION_DENIED      3
+#define SSH2_FX_FAILURE                        4
+#define SSH2_FX_BAD_MESSAGE            5
+#define SSH2_FX_NO_CONNECTION          6
+#define SSH2_FX_CONNECTION_LOST                7
+#define SSH2_FX_OP_UNSUPPORTED         8
+#define SSH2_FX_MAX                    8
diff --git a/openssh/ssh-add.1 b/openssh/ssh-add.1
new file mode 100644 (file)
index 0000000..b842080
--- /dev/null
@@ -0,0 +1,148 @@
+.\"    $OpenBSD: ssh-add.1,v 1.27 2001/08/23 18:08:59 stevesk Exp $
+.\"
+.\"  -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\"                    All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose.  Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell.  All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd September 25, 1999
+.Dt SSH-ADD 1
+.Os
+.Sh NAME
+.Nm ssh-add
+.Nd adds RSA or DSA identities to the authentication agent
+.Sh SYNOPSIS
+.Nm ssh-add
+.Op Fl lLdD
+.Op Ar
+.Nm ssh-add
+.Fl s Ar reader
+.Nm ssh-add
+.Fl e Ar reader
+.Sh DESCRIPTION
+.Nm
+adds RSA or DSA identities to the authentication agent,
+.Xr ssh-agent 1 .
+When run without arguments, it adds the file
+.Pa $HOME/.ssh/identity .
+Alternative file names can be given on the command line.
+If any file requires a passphrase,
+.Nm
+asks for the passphrase from the user.
+The passphrase is read from the user's tty.
+.Nm
+retries the last passphrase if multiple identity files are given.
+.Pp
+The authentication agent must be running and must be an ancestor of
+the current process for
+.Nm
+to work.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl l
+Lists fingerprints of all identities currently represented by the agent.
+.It Fl L
+Lists public key parameters of all identities currently represented by the agent.
+.It Fl d
+Instead of adding the identity, removes the identity from the agent.
+.It Fl D
+Deletes all identities from the agent.
+.It Fl s Ar reader
+Add key in smartcard
+.Ar reader .
+.It Fl e Ar reader
+Remove key in smartcard
+.Ar reader .
+.El
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $HOME/.ssh/identity
+Contains the protocol version 1 RSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+Note that
+.Nm
+ignores this file if it is accessible by others.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file.
+This is the default file added by
+.Nm
+when no other files have been specified.
+.It Pa $HOME/.ssh/id_dsa
+Contains the protocol version 2 DSA authentication identity of the user.
+.It Pa $HOME/.ssh/id_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev "DISPLAY" and "SSH_ASKPASS"
+If
+.Nm
+needs a passphrase, it will read the passphrase from the current
+terminal if it was run from a terminal.
+If
+.Nm
+does not have a terminal associated with it but
+.Ev DISPLAY
+and
+.Ev SSH_ASKPASS
+are set, it will execute the program specified by
+.Ev SSH_ASKPASS
+and open an X11 window to read the passphrase.
+This is particularly useful when calling
+.Nm
+from a
+.Pa .Xsession
+or related script.
+(Note that on some machines it
+may be necessary to redirect the input from
+.Pa /dev/null
+to make this work.)
+.El
+.Sh AUTHORS
+OpenSSH is a derivative of the original and free
+ssh 1.2.12 release by Tatu Ylonen.
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
+Theo de Raadt and Dug Song
+removed many bugs, re-added newer features and
+created OpenSSH.
+Markus Friedl contributed the support for SSH
+protocol versions 1.5 and 2.0.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
diff --git a/openssh/ssh-add.c b/openssh/ssh-add.c
new file mode 100644 (file)
index 0000000..585b714
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Adds an identity to the authentication server, or removes an identity.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * SSH2 implementation,
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-add.c,v 1.46 2001/10/02 08:38:50 djm Exp $");
+
+#include <openssl/evp.h>
+
+#include "ssh.h"
+#include "rsa.h"
+#include "log.h"
+#include "xmalloc.h"
+#include "key.h"
+#include "authfd.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "readpass.h"
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+/* argv0 */
+extern char *__progname;
+
+/* we keep a cache of one passphrases */
+static char *pass = NULL;
+static void
+clear_pass(void)
+{
+       if (pass) {
+               memset(pass, 0, strlen(pass));
+               xfree(pass);
+               pass = NULL;
+       }
+}
+
+static int
+delete_file(AuthenticationConnection *ac, const char *filename)
+{
+       Key *public;
+       char *comment = NULL;
+       int ret = -1;
+
+       public = key_load_public(filename, &comment);
+       if (public == NULL) {
+               printf("Bad key file %s\n", filename);
+               return -1;
+       }
+       if (ssh_remove_identity(ac, public)) {
+               fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
+               ret = 0;
+       } else
+               fprintf(stderr, "Could not remove identity: %s\n", filename);
+
+       key_free(public);
+       xfree(comment);
+       
+       return ret;
+}
+
+/* Send a request to remove all identities. */
+static int
+delete_all(AuthenticationConnection *ac)
+{
+       int ret = -1;
+
+       if (ssh_remove_all_identities(ac, 1))
+               ret = 0;
+       /* ignore error-code for ssh2 */
+       ssh_remove_all_identities(ac, 2);
+
+       if (ret == 0)
+               fprintf(stderr, "All identities removed.\n");
+       else
+               fprintf(stderr, "Failed to remove all identities.\n");
+
+       return ret;
+}
+
+static int
+add_file(AuthenticationConnection *ac, const char *filename)
+{
+       struct stat st;
+       Key *private;
+       char *comment = NULL;
+       char msg[1024];
+       int ret = -1;
+
+       if (stat(filename, &st) < 0) {
+               perror(filename);
+               return -1;
+       }
+       /* At first, try empty passphrase */
+       private = key_load_private(filename, "", &comment);
+       if (comment == NULL)
+               comment = xstrdup(filename);
+       /* try last */
+       if (private == NULL && pass != NULL)
+               private = key_load_private(filename, pass, NULL);
+       if (private == NULL) {
+               /* clear passphrase since it did not work */
+               clear_pass();
+               snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ",
+                  comment);
+               for (;;) {
+                       pass = read_passphrase(msg, RP_ALLOW_STDIN);
+                       if (strcmp(pass, "") == 0) {
+                               clear_pass();
+                               xfree(comment);
+                               return -1;
+                       }
+                       private = key_load_private(filename, pass, &comment);
+                       if (private != NULL)
+                               break;
+                       clear_pass();
+                       strlcpy(msg, "Bad passphrase, try again: ", sizeof msg);
+               }
+       }
+       if (ssh_add_identity(ac, private, comment)) {
+               fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
+               ret = 0;
+       } else
+               fprintf(stderr, "Could not add identity: %s\n", filename);
+
+       xfree(comment);
+       key_free(private);
+       
+       return ret;
+}
+
+static int
+update_card(AuthenticationConnection *ac, int add, const char *id)
+{
+       if (ssh_update_card(ac, add, id)) {
+               fprintf(stderr, "Card %s: %s\n",
+                    add ? "added" : "removed", id);
+               return 0;
+       } else {
+               fprintf(stderr, "Could not %s card: %s\n",
+                    add ? "add" : "remove", id);
+               return -1;
+       }
+}
+
+static void
+list_identities(AuthenticationConnection *ac, int do_fp)
+{
+       Key *key;
+       char *comment, *fp;
+       int had_identities = 0;
+       int version;
+
+       for (version = 1; version <= 2; version++) {
+               for (key = ssh_get_first_identity(ac, &comment, version);
+                    key != NULL;
+                    key = ssh_get_next_identity(ac, &comment, version)) {
+                       had_identities = 1;
+                       if (do_fp) {
+                               fp = key_fingerprint(key, SSH_FP_MD5,
+                                   SSH_FP_HEX);
+                               printf("%d %s %s (%s)\n",
+                                   key_size(key), fp, comment, key_type(key));
+                               xfree(fp);
+                       } else {
+                               if (!key_write(key, stdout))
+                                       fprintf(stderr, "key_write failed");
+                               fprintf(stdout, " %s\n", comment);
+                       }
+                       key_free(key);
+                       xfree(comment);
+               }
+       }
+       if (!had_identities)
+               printf("The agent has no identities.\n");
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: %s [options]\n", __progname);
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "  -l          List fingerprints of all identities.\n");
+       fprintf(stderr, "  -L          List public key parameters of all identities.\n");
+       fprintf(stderr, "  -d          Delete identity.\n");
+       fprintf(stderr, "  -D          Delete all identities.\n");
+#ifdef SMARTCARD
+       fprintf(stderr, "  -s reader   Add key in smartcard reader.\n");
+       fprintf(stderr, "  -e reader   Remove key in smartcard reader.\n");
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind;
+       AuthenticationConnection *ac = NULL;
+       struct passwd *pw;
+       char buf[1024];
+       char *sc_reader_id = NULL;
+       int i, ch, deleting = 0, ret = 0;
+
+       __progname = get_progname(argv[0]);
+       init_rng();
+       seed_rng();
+
+       SSLeay_add_all_algorithms();
+
+       /* At first, get a connection to the authentication agent. */
+       ac = ssh_get_authentication_connection();
+       if (ac == NULL) {
+               fprintf(stderr, "Could not open a connection to your authentication agent.\n");
+               exit(1);
+       }
+        while ((ch = getopt(argc, argv, "lLdDe:s:")) != -1) {
+               switch (ch) {
+               case 'l':
+               case 'L':
+                       list_identities(ac, ch == 'l' ? 1 : 0);
+                       goto done;
+                       break;
+               case 'd':
+                       deleting = 1;
+                       break;
+               case 'D':
+                       if (delete_all(ac) == -1)
+                               ret = 1;
+                       goto done;
+                       break;
+               case 's':
+                       sc_reader_id = optarg;
+                       break;
+               case 'e':
+                       deleting = 1; 
+                       sc_reader_id = optarg;
+                       break;
+               default:
+                       usage();
+                       ret = 1;
+                       goto done;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if (sc_reader_id != NULL) {
+               if (update_card(ac, !deleting, sc_reader_id) == -1)
+                       ret = 1;
+               goto done;
+       }
+       if (argc == 0) {
+               pw = getpwuid(getuid());
+               if (!pw) {
+                       fprintf(stderr, "No user found with uid %u\n",
+                           (u_int)getuid());
+                       ret = 1;
+                       goto done;
+               }
+               snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY);
+               if (deleting) {
+                       if (delete_file(ac, buf) == -1)
+                               ret = 1;
+               } else {
+                       if (add_file(ac, buf) == -1)
+                               ret = 1;
+               }
+       } else {
+               for (i = 0; i < argc; i++) {
+                       if (deleting) {
+                               if (delete_file(ac, argv[i]) == -1)
+                                       ret = 1;
+                       } else {
+                               if (add_file(ac, argv[i]) == -1)
+                                       ret = 1;
+                       }
+               }
+       }
+       clear_pass();
+
+done:
+       ssh_close_authentication_connection(ac);
+       return ret;
+}
diff --git a/openssh/ssh-agent.1 b/openssh/ssh-agent.1
new file mode 100644 (file)
index 0000000..00c1992
--- /dev/null
@@ -0,0 +1,182 @@
+.\" $OpenBSD: ssh-agent.1,v 1.28 2001/09/05 06:23:07 deraadt Exp $
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\"                    All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose.  Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell.  All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd September 25, 1999
+.Dt SSH-AGENT 1
+.Os
+.Sh NAME
+.Nm ssh-agent
+.Nd authentication agent
+.Sh SYNOPSIS
+.Nm ssh-agent
+.Op Fl c Li | Fl s
+.Op Fl d
+.Op Ar command Op Ar args ...
+.Nm ssh-agent
+.Op Fl c Li | Fl s
+.Fl k
+.Sh DESCRIPTION
+.Nm
+is a program to hold private keys used for public key authentication
+(RSA, DSA).
+The idea is that
+.Nm
+is started in the beginning of an X-session or a login session, and
+all other windows or programs are started as clients to the ssh-agent
+program.
+Through use of environment variables the agent can be located
+and automatically used for authentication when logging in to other
+machines using
+.Xr ssh 1 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c
+Generate C-shell commands on
+.Dv stdout .
+This is the default if
+.Ev SHELL
+looks like it's a csh style of shell.
+.It Fl s
+Generate Bourne shell commands on
+.Dv stdout .
+This is the default if
+.Ev SHELL
+does not look like it's a csh style of shell.
+.It Fl k
+Kill the current agent (given by the
+.Ev SSH_AGENT_PID
+environment variable).
+.It Fl d
+Debug mode.  When this option is specified
+.Nm
+will not fork.
+.El
+.Pp
+If a commandline is given, this is executed as a subprocess of the agent.
+When the command dies, so does the agent.
+.Pp
+The agent initially does not have any private keys.
+Keys are added using
+.Xr ssh-add 1 .
+When executed without arguments,
+.Xr ssh-add 1
+adds the
+.Pa $HOME/.ssh/identity
+file.
+If the identity has a passphrase,
+.Xr ssh-add 1
+asks for the passphrase (using a small X11 application if running
+under X11, or from the terminal if running without X).
+It then sends the identity to the agent.
+Several identities can be stored in the
+agent; the agent can automatically use any of these identities.
+.Ic ssh-add -l
+displays the identities currently held by the agent.
+.Pp
+The idea is that the agent is run in the user's local PC, laptop, or
+terminal.
+Authentication data need not be stored on any other
+machine, and authentication passphrases never go over the network.
+However, the connection to the agent is forwarded over SSH
+remote logins, and the user can thus use the privileges given by the
+identities anywhere in the network in a secure way.
+.Pp
+There are two main ways to get an agent setup:
+Either the agent starts a new subcommand into which some environment
+variables are exported, or the agent prints the needed shell commands
+(either
+.Xr sh 1
+or
+.Xr csh 1
+syntax can be generated) which can be evalled in the calling shell.
+Later
+.Xr ssh 1
+looks at these variables and uses them to establish a connection to the agent.
+.Pp
+A unix-domain socket is created
+.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> ,
+and the name of this socket is stored in the
+.Ev SSH_AUTH_SOCK
+environment
+variable.
+The socket is made accessible only to the current user.
+This method is easily abused by root or another instance of the same
+user.
+.Pp
+The
+.Ev SSH_AGENT_PID
+environment variable holds the agent's PID.
+.Pp
+The agent exits automatically when the command given on the command
+line terminates.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $HOME/.ssh/identity
+Contains the protocol version 1 RSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file.
+This file is not used by
+.Nm
+but is normally added to the agent using
+.Xr ssh-add 1
+at login time.
+.It Pa $HOME/.ssh/id_dsa
+Contains the protocol version 2 DSA authentication identity of the user.
+.It Pa $HOME/.ssh/id_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+.It Pa /tmp/ssh-XXXXXXXX/agent.<pid>
+Unix-domain sockets used to contain the connection to the
+authentication agent.
+These sockets should only be readable by the owner.
+The sockets should get automatically removed when the agent exits.
+.El
+.Sh AUTHORS
+OpenSSH is a derivative of the original and free
+ssh 1.2.12 release by Tatu Ylonen.
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
+Theo de Raadt and Dug Song
+removed many bugs, re-added newer features and
+created OpenSSH.
+Markus Friedl contributed the support for SSH
+protocol versions 1.5 and 2.0.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
diff --git a/openssh/ssh-agent.c b/openssh/ssh-agent.c
new file mode 100644 (file)
index 0000000..a004e32
--- /dev/null
@@ -0,0 +1,1045 @@
+/*     $OpenBSD: ssh-agent.c,v 1.72 2001/08/03 10:31:30 jakob Exp $    */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * The authentication agent program.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-agent.c,v 1.72 2001/08/03 10:31:30 jakob Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+#include "ssh.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "xmalloc.h"
+#include "packet.h"
+#include "getput.h"
+#include "mpaux.h"
+#include "key.h"
+#include "authfd.h"
+#include "cipher.h"
+#include "kex.h"
+#include "compat.h"
+#include "log.h"
+
+#ifdef SMARTCARD
+#include <openssl/engine.h>
+#include "scard.h"
+#endif
+
+typedef struct {
+       int fd;
+       enum {
+               AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
+       } type;
+       Buffer input;
+       Buffer output;
+} SocketEntry;
+
+u_int sockets_alloc = 0;
+SocketEntry *sockets = NULL;
+
+typedef struct {
+       Key *key;
+       char *comment;
+} Identity;
+
+typedef struct {
+       int nentries;
+       Identity *identities;
+} Idtab;
+
+/* private key table, one per protocol version */
+Idtab idtable[3];
+
+int max_fd = 0;
+
+/* pid of shell == parent of agent */
+pid_t parent_pid = -1;
+
+/* pathname and directory for AUTH_SOCKET */
+char socket_name[1024];
+char socket_dir[1024];
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+static void
+idtab_init(void)
+{
+       int i;
+       for (i = 0; i <=2; i++){
+               idtable[i].identities = NULL;
+               idtable[i].nentries = 0;
+       }
+}
+
+/* return private key table for requested protocol version */
+static Idtab *
+idtab_lookup(int version)
+{
+       if (version < 1 || version > 2)
+               fatal("internal error, bad protocol version %d", version);
+       return &idtable[version];
+}
+
+/* return matching private key for given public key */
+static Key *
+lookup_private_key(Key *key, int *idx, int version)
+{
+       int i;
+       Idtab *tab = idtab_lookup(version);
+       for (i = 0; i < tab->nentries; i++) {
+               if (key_equal(key, tab->identities[i].key)) {
+                       if (idx != NULL)
+                               *idx = i;
+                       return tab->identities[i].key;
+               }
+       }
+       return NULL;
+}
+
+/* send list of supported public keys to 'client' */
+static void
+process_request_identities(SocketEntry *e, int version)
+{
+       Idtab *tab = idtab_lookup(version);
+       Buffer msg;
+       int i;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, (version == 1) ?
+           SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
+       buffer_put_int(&msg, tab->nentries);
+       for (i = 0; i < tab->nentries; i++) {
+               Identity *id = &tab->identities[i];
+               if (id->key->type == KEY_RSA1) {
+                       buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
+                       buffer_put_bignum(&msg, id->key->rsa->e);
+                       buffer_put_bignum(&msg, id->key->rsa->n);
+               } else {
+                       u_char *blob;
+                       u_int blen;
+                       key_to_blob(id->key, &blob, &blen);
+                       buffer_put_string(&msg, blob, blen);
+                       xfree(blob);
+               }
+               buffer_put_cstring(&msg, id->comment);
+       }
+       buffer_put_int(&e->output, buffer_len(&msg));
+       buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+       buffer_free(&msg);
+}
+
+/* ssh1 only */
+static void
+process_authentication_challenge1(SocketEntry *e)
+{
+       Key *key, *private;
+       BIGNUM *challenge;
+       int i, len;
+       Buffer msg;
+       MD5_CTX md;
+       u_char buf[32], mdbuf[16], session_id[16];
+       u_int response_type;
+
+       buffer_init(&msg);
+       key = key_new(KEY_RSA1);
+       challenge = BN_new();
+
+       buffer_get_int(&e->input);                              /* ignored */
+       buffer_get_bignum(&e->input, key->rsa->e);
+       buffer_get_bignum(&e->input, key->rsa->n);
+       buffer_get_bignum(&e->input, challenge);
+
+       /* Only protocol 1.1 is supported */
+       if (buffer_len(&e->input) == 0)
+               goto failure;
+       buffer_get(&e->input, (char *) session_id, 16);
+       response_type = buffer_get_int(&e->input);
+       if (response_type != 1)
+               goto failure;
+
+       private = lookup_private_key(key, NULL, 1);
+       if (private != NULL) {
+               /* Decrypt the challenge using the private key. */
+               if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
+                       goto failure;
+
+               /* The response is MD5 of decrypted challenge plus session id. */
+               len = BN_num_bytes(challenge);
+               if (len <= 0 || len > 32) {
+                       log("process_authentication_challenge: bad challenge length %d", len);
+                       goto failure;
+               }
+               memset(buf, 0, 32);
+               BN_bn2bin(challenge, buf + 32 - len);
+               MD5_Init(&md);
+               MD5_Update(&md, buf, 32);
+               MD5_Update(&md, session_id, 16);
+               MD5_Final(mdbuf, &md);
+
+               /* Send the response. */
+               buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
+               for (i = 0; i < 16; i++)
+                       buffer_put_char(&msg, mdbuf[i]);
+               goto send;
+       }
+
+failure:
+       /* Unknown identity or protocol error.  Send failure. */
+       buffer_put_char(&msg, SSH_AGENT_FAILURE);
+send:
+       buffer_put_int(&e->output, buffer_len(&msg));
+       buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+       key_free(key);
+       BN_clear_free(challenge);
+       buffer_free(&msg);
+}
+
+/* ssh2 only */
+static void
+process_sign_request2(SocketEntry *e)
+{
+       extern int datafellows;
+       Key *key, *private;
+       u_char *blob, *data, *signature = NULL;
+       u_int blen, dlen, slen = 0;
+       int flags;
+       Buffer msg;
+       int ok = -1;
+
+       datafellows = 0;
+
+       blob = buffer_get_string(&e->input, &blen);
+       data = buffer_get_string(&e->input, &dlen);
+
+       flags = buffer_get_int(&e->input);
+       if (flags & SSH_AGENT_OLD_SIGNATURE)
+               datafellows = SSH_BUG_SIGBLOB;
+
+       key = key_from_blob(blob, blen);
+       if (key != NULL) {
+               private = lookup_private_key(key, NULL, 2);
+               if (private != NULL)
+                       ok = key_sign(private, &signature, &slen, data, dlen);
+       }
+       key_free(key);
+       buffer_init(&msg);
+       if (ok == 0) {
+               buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
+               buffer_put_string(&msg, signature, slen);
+       } else {
+               buffer_put_char(&msg, SSH_AGENT_FAILURE);
+       }
+       buffer_put_int(&e->output, buffer_len(&msg));
+       buffer_append(&e->output, buffer_ptr(&msg),
+           buffer_len(&msg));
+       buffer_free(&msg);
+       xfree(data);
+       xfree(blob);
+       if (signature != NULL)
+               xfree(signature);
+}
+
+/* shared */
+static void
+process_remove_identity(SocketEntry *e, int version)
+{
+       Key *key = NULL, *private;
+       u_char *blob;
+       u_int blen;
+       u_int bits;
+       int success = 0;
+
+       switch(version){
+       case 1:
+               key = key_new(KEY_RSA1);
+               bits = buffer_get_int(&e->input);
+               buffer_get_bignum(&e->input, key->rsa->e);
+               buffer_get_bignum(&e->input, key->rsa->n);
+
+               if (bits != key_size(key))
+                       log("Warning: identity keysize mismatch: actual %d, announced %d",
+                           key_size(key), bits);
+               break;
+       case 2:
+               blob = buffer_get_string(&e->input, &blen);
+               key = key_from_blob(blob, blen);
+               xfree(blob);
+               break;
+       }
+       if (key != NULL) {
+               int idx;
+               private = lookup_private_key(key, &idx, version);
+               if (private != NULL) {
+                       /*
+                        * We have this key.  Free the old key.  Since we
+                        * don\'t want to leave empty slots in the middle of
+                        * the array, we actually free the key there and move
+                        * all the entries between the empty slot and the end
+                        * of the array.
+                        */
+                       Idtab *tab = idtab_lookup(version);
+                       key_free(tab->identities[idx].key);
+                       xfree(tab->identities[idx].comment);
+                       if (tab->nentries < 1)
+                               fatal("process_remove_identity: "
+                                   "internal error: tab->nentries %d",
+                                   tab->nentries);
+                       if (idx != tab->nentries - 1) {
+                               int i;
+                               for (i = idx; i < tab->nentries - 1; i++)
+                                       tab->identities[i] = tab->identities[i+1];
+                       }
+                       tab->identities[tab->nentries - 1].key = NULL;
+                       tab->identities[tab->nentries - 1].comment = NULL;
+                       tab->nentries--;
+                       success = 1;
+               }
+               key_free(key);
+       }
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_all_identities(SocketEntry *e, int version)
+{
+       u_int i;
+       Idtab *tab = idtab_lookup(version);
+
+       /* Loop over all identities and clear the keys. */
+       for (i = 0; i < tab->nentries; i++) {
+               key_free(tab->identities[i].key);
+               xfree(tab->identities[i].comment);
+       }
+
+       /* Mark that there are no identities. */
+       tab->nentries = 0;
+
+       /* Send success. */
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
+       return;
+}
+
+static void
+process_add_identity(SocketEntry *e, int version)
+{
+       Key *k = NULL;
+       char *type_name;
+       char *comment;
+       int type, success = 0;
+       Idtab *tab = idtab_lookup(version);
+
+       switch (version) {
+       case 1:
+               k = key_new_private(KEY_RSA1);
+               buffer_get_int(&e->input);                      /* ignored */
+               buffer_get_bignum(&e->input, k->rsa->n);
+               buffer_get_bignum(&e->input, k->rsa->e);
+               buffer_get_bignum(&e->input, k->rsa->d);
+               buffer_get_bignum(&e->input, k->rsa->iqmp);
+
+               /* SSH and SSL have p and q swapped */
+               buffer_get_bignum(&e->input, k->rsa->q);        /* p */
+               buffer_get_bignum(&e->input, k->rsa->p);        /* q */
+
+               /* Generate additional parameters */
+               rsa_generate_additional_parameters(k->rsa);
+               break;
+       case 2:
+               type_name = buffer_get_string(&e->input, NULL);
+               type = key_type_from_name(type_name);
+               xfree(type_name);
+               switch(type) {
+               case KEY_DSA:
+                       k = key_new_private(type);
+                       buffer_get_bignum2(&e->input, k->dsa->p);
+                       buffer_get_bignum2(&e->input, k->dsa->q);
+                       buffer_get_bignum2(&e->input, k->dsa->g);
+                       buffer_get_bignum2(&e->input, k->dsa->pub_key);
+                       buffer_get_bignum2(&e->input, k->dsa->priv_key);
+                       break;
+               case KEY_RSA:
+                       k = key_new_private(type);
+                       buffer_get_bignum2(&e->input, k->rsa->n);
+                       buffer_get_bignum2(&e->input, k->rsa->e);
+                       buffer_get_bignum2(&e->input, k->rsa->d);
+                       buffer_get_bignum2(&e->input, k->rsa->iqmp);
+                       buffer_get_bignum2(&e->input, k->rsa->p);
+                       buffer_get_bignum2(&e->input, k->rsa->q);
+
+                       /* Generate additional parameters */
+                       rsa_generate_additional_parameters(k->rsa);
+                       break;
+               default:
+                       buffer_clear(&e->input);
+                       goto send;
+               }
+               break;
+       }
+       comment = buffer_get_string(&e->input, NULL);
+       if (k == NULL) {
+               xfree(comment);
+               goto send;
+       }
+       success = 1;
+       if (lookup_private_key(k, NULL, version) == NULL) {
+               if (tab->nentries == 0)
+                       tab->identities = xmalloc(sizeof(Identity));
+               else
+                       tab->identities = xrealloc(tab->identities,
+                           (tab->nentries + 1) * sizeof(Identity));
+               tab->identities[tab->nentries].key = k;
+               tab->identities[tab->nentries].comment = comment;
+               /* Increment the number of identities. */
+               tab->nentries++;
+       } else {
+               key_free(k);
+               xfree(comment);
+       }
+send:
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+
+#ifdef SMARTCARD
+static void
+process_add_smartcard_key (SocketEntry *e)
+{
+       Idtab *tab;
+       Key *n = NULL, *k = NULL;
+       char *sc_reader_id = NULL;
+       int success = 0;
+       
+       sc_reader_id = buffer_get_string(&e->input, NULL);
+       k = sc_get_key(sc_reader_id);
+       xfree(sc_reader_id);
+
+       if (k == NULL) {
+               error("sc_get_pubkey failed");
+               goto send;
+       }
+       success = 1;
+
+       tab = idtab_lookup(1);
+       k->type = KEY_RSA1;
+       if (lookup_private_key(k, NULL, 1) == NULL) {
+               if (tab->nentries == 0)
+                       tab->identities = xmalloc(sizeof(Identity));
+               else
+                       tab->identities = xrealloc(tab->identities,
+                           (tab->nentries + 1) * sizeof(Identity));
+               n = key_new(KEY_RSA1);
+               BN_copy(n->rsa->n, k->rsa->n);
+               BN_copy(n->rsa->e, k->rsa->e);
+               RSA_set_method(n->rsa, sc_get_engine());
+               tab->identities[tab->nentries].key = n;
+               tab->identities[tab->nentries].comment =
+                   xstrdup("rsa1 smartcard");
+               tab->nentries++;
+       }
+       k->type = KEY_RSA;
+       tab = idtab_lookup(2);
+       if (lookup_private_key(k, NULL, 2) == NULL) {
+               if (tab->nentries == 0)
+                       tab->identities = xmalloc(sizeof(Identity));
+               else
+                       tab->identities = xrealloc(tab->identities,
+                           (tab->nentries + 1) * sizeof(Identity));
+               n = key_new(KEY_RSA);
+               BN_copy(n->rsa->n, k->rsa->n);
+               BN_copy(n->rsa->e, k->rsa->e);
+               RSA_set_method(n->rsa, sc_get_engine());
+               tab->identities[tab->nentries].key = n;
+               tab->identities[tab->nentries].comment =
+                   xstrdup("rsa smartcard");
+               tab->nentries++;
+       }
+       key_free(k);
+send:
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_smartcard_key(SocketEntry *e)
+{
+       Key *k = NULL, *private;
+       int idx;
+       int success = 0;
+       char *sc_reader_id = NULL;
+
+       sc_reader_id = buffer_get_string(&e->input, NULL);
+       k = sc_get_key(sc_reader_id);
+       xfree(sc_reader_id);
+
+       if (k == NULL) {
+               error("sc_get_pubkey failed");
+       } else {
+               k->type = KEY_RSA1;
+               private = lookup_private_key(k, &idx, 1);
+               if (private != NULL) {
+                       Idtab *tab = idtab_lookup(1);
+                       key_free(tab->identities[idx].key);
+                       xfree(tab->identities[idx].comment);
+                       if (idx != tab->nentries)
+                               tab->identities[idx] = tab->identities[tab->nentries];
+                       tab->nentries--;
+                       success = 1;
+               }
+               k->type = KEY_RSA;
+               private = lookup_private_key(k, &idx, 2);
+               if (private != NULL) {
+                       Idtab *tab = idtab_lookup(2);
+                       key_free(tab->identities[idx].key);
+                       xfree(tab->identities[idx].comment);
+                       if (idx != tab->nentries)
+                               tab->identities[idx] = tab->identities[tab->nentries];
+                       tab->nentries--;
+                       success = 1;
+               }
+               key_free(k);
+       }
+
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif /* SMARTCARD */
+
+/* dispatch incoming messages */
+
+static void
+process_message(SocketEntry *e)
+{
+       u_int msg_len;
+       u_int type;
+       u_char *cp;
+       if (buffer_len(&e->input) < 5)
+               return;         /* Incomplete message. */
+       cp = (u_char *) buffer_ptr(&e->input);
+       msg_len = GET_32BIT(cp);
+       if (msg_len > 256 * 1024) {
+               shutdown(e->fd, SHUT_RDWR);
+               close(e->fd);
+               e->type = AUTH_UNUSED;
+               return;
+       }
+       if (buffer_len(&e->input) < msg_len + 4)
+               return;
+       buffer_consume(&e->input, 4);
+       type = buffer_get_char(&e->input);
+
+       debug("type %d", type);
+       switch (type) {
+       /* ssh1 */
+       case SSH_AGENTC_RSA_CHALLENGE:
+               process_authentication_challenge1(e);
+               break;
+       case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
+               process_request_identities(e, 1);
+               break;
+       case SSH_AGENTC_ADD_RSA_IDENTITY:
+               process_add_identity(e, 1);
+               break;
+       case SSH_AGENTC_REMOVE_RSA_IDENTITY:
+               process_remove_identity(e, 1);
+               break;
+       case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
+               process_remove_all_identities(e, 1);
+               break;
+       /* ssh2 */
+       case SSH2_AGENTC_SIGN_REQUEST:
+               process_sign_request2(e);
+               break;
+       case SSH2_AGENTC_REQUEST_IDENTITIES:
+               process_request_identities(e, 2);
+               break;
+       case SSH2_AGENTC_ADD_IDENTITY:
+               process_add_identity(e, 2);
+               break;
+       case SSH2_AGENTC_REMOVE_IDENTITY:
+               process_remove_identity(e, 2);
+               break;
+       case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
+               process_remove_all_identities(e, 2);
+               break;
+#ifdef SMARTCARD
+       case SSH_AGENTC_ADD_SMARTCARD_KEY:
+               process_add_smartcard_key(e);
+               break; 
+       case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
+               process_remove_smartcard_key(e);
+               break; 
+#endif /* SMARTCARD */
+       default:
+               /* Unknown message.  Respond with failure. */
+               error("Unknown message %d", type);
+               buffer_clear(&e->input);
+               buffer_put_int(&e->output, 1);
+               buffer_put_char(&e->output, SSH_AGENT_FAILURE);
+               break;
+       }
+}
+
+static void
+new_socket(int type, int fd)
+{
+       u_int i, old_alloc;
+       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+               error("fcntl O_NONBLOCK: %s", strerror(errno));
+
+       if (fd > max_fd)
+               max_fd = fd;
+
+       for (i = 0; i < sockets_alloc; i++)
+               if (sockets[i].type == AUTH_UNUSED) {
+                       sockets[i].fd = fd;
+                       sockets[i].type = type;
+                       buffer_init(&sockets[i].input);
+                       buffer_init(&sockets[i].output);
+                       return;
+               }
+       old_alloc = sockets_alloc;
+       sockets_alloc += 10;
+       if (sockets)
+               sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
+       else
+               sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
+       for (i = old_alloc; i < sockets_alloc; i++)
+               sockets[i].type = AUTH_UNUSED;
+       sockets[old_alloc].type = type;
+       sockets[old_alloc].fd = fd;
+       buffer_init(&sockets[old_alloc].input);
+       buffer_init(&sockets[old_alloc].output);
+}
+
+static int
+prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
+{
+       u_int i, sz;
+       int n = 0;
+
+       for (i = 0; i < sockets_alloc; i++) {
+               switch (sockets[i].type) {
+               case AUTH_SOCKET:
+               case AUTH_CONNECTION:
+                       n = MAX(n, sockets[i].fd);
+                       break;
+               case AUTH_UNUSED:
+                       break;
+               default:
+                       fatal("Unknown socket type %d", sockets[i].type);
+                       break;
+               }
+       }
+
+       sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
+       if (*fdrp == NULL || sz > *nallocp) {
+               if (*fdrp)
+                       xfree(*fdrp);
+               if (*fdwp)
+                       xfree(*fdwp);
+               *fdrp = xmalloc(sz);
+               *fdwp = xmalloc(sz);
+               *nallocp = sz;
+       }
+       if (n < *fdl)
+               debug("XXX shrink: %d < %d", n, *fdl);
+       *fdl = n;
+       memset(*fdrp, 0, sz);
+       memset(*fdwp, 0, sz);
+
+       for (i = 0; i < sockets_alloc; i++) {
+               switch (sockets[i].type) {
+               case AUTH_SOCKET:
+               case AUTH_CONNECTION:
+                       FD_SET(sockets[i].fd, *fdrp);
+                       if (buffer_len(&sockets[i].output) > 0)
+                               FD_SET(sockets[i].fd, *fdwp);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return (1);
+}
+
+static void
+after_select(fd_set *readset, fd_set *writeset)
+{
+       u_int i;
+       int len, sock;
+       socklen_t slen;
+       char buf[1024];
+       struct sockaddr_un sunaddr;
+
+       for (i = 0; i < sockets_alloc; i++)
+               switch (sockets[i].type) {
+               case AUTH_UNUSED:
+                       break;
+               case AUTH_SOCKET:
+                       if (FD_ISSET(sockets[i].fd, readset)) {
+                               slen = sizeof(sunaddr);
+                               sock = accept(sockets[i].fd,
+                                   (struct sockaddr *) &sunaddr, &slen);
+                               if (sock < 0) {
+                                       perror("accept from AUTH_SOCKET");
+                                       break;
+                               }
+                               new_socket(AUTH_CONNECTION, sock);
+                       }
+                       break;
+               case AUTH_CONNECTION:
+                       if (buffer_len(&sockets[i].output) > 0 &&
+                           FD_ISSET(sockets[i].fd, writeset)) {
+                               do {
+                                       len = write(sockets[i].fd,
+                                           buffer_ptr(&sockets[i].output),
+                                           buffer_len(&sockets[i].output));
+                                       if (len == -1 && (errno == EAGAIN ||
+                                           errno == EINTR))
+                                               continue;
+                                       break;
+                               } while (1);
+                               if (len <= 0) {
+                                       shutdown(sockets[i].fd, SHUT_RDWR);
+                                       close(sockets[i].fd);
+                                       sockets[i].type = AUTH_UNUSED;
+                                       buffer_free(&sockets[i].input);
+                                       buffer_free(&sockets[i].output);
+                                       break;
+                               }
+                               buffer_consume(&sockets[i].output, len);
+                       }
+                       if (FD_ISSET(sockets[i].fd, readset)) {
+                               do {
+                                       len = read(sockets[i].fd, buf, sizeof(buf));
+                                       if (len == -1 && (errno == EAGAIN ||
+                                           errno == EINTR))
+                                               continue;
+                                       break;
+                               } while (1);
+                               if (len <= 0) {
+                                       shutdown(sockets[i].fd, SHUT_RDWR);
+                                       close(sockets[i].fd);
+                                       sockets[i].type = AUTH_UNUSED;
+                                       buffer_free(&sockets[i].input);
+                                       buffer_free(&sockets[i].output);
+                                       break;
+                               }
+                               buffer_append(&sockets[i].input, buf, len);
+                               process_message(&sockets[i]);
+                       }
+                       break;
+               default:
+                       fatal("Unknown type %d", sockets[i].type);
+               }
+}
+
+static void
+cleanup_socket(void)
+{
+       if (socket_name[0])
+               unlink(socket_name);
+       if (socket_dir[0])
+               rmdir(socket_dir);
+}
+
+static void
+cleanup_exit(int i)
+{
+       cleanup_socket();
+       exit(i);
+}
+
+static void
+cleanup_handler(int sig)
+{
+       cleanup_socket();
+       _exit(2);
+}
+
+static void
+check_parent_exists(int sig)
+{
+       int save_errno = errno;
+
+       if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
+               /* printf("Parent has died - Authentication agent exiting.\n"); */
+               cleanup_handler(sig); /* safe */
+       }
+       signal(SIGALRM, check_parent_exists);
+       alarm(10);
+       errno = save_errno;
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: %s [options] [command [args ...]]\n",
+           __progname);
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "  -c          Generate C-shell commands on stdout.\n");
+       fprintf(stderr, "  -s          Generate Bourne shell commands on stdout.\n");
+       fprintf(stderr, "  -k          Kill the current agent.\n");
+       fprintf(stderr, "  -d          Debug mode.\n");
+       exit(1);
+}
+
+int
+main(int ac, char **av)
+{
+       int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
+       struct sockaddr_un sunaddr;
+#ifdef HAVE_SETRLIMIT
+       struct rlimit rlim;
+#endif
+#ifdef HAVE_CYGWIN
+       int prev_mask;
+#endif
+       pid_t pid;
+       char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
+       extern int optind;
+       fd_set *readsetp = NULL, *writesetp = NULL;
+
+       SSLeay_add_all_algorithms();
+
+       __progname = get_progname(av[0]);
+       init_rng();
+       seed_rng();
+
+#ifdef __GNU_LIBRARY__
+       while ((ch = getopt(ac, av, "+cdks")) != -1) {
+#else /* __GNU_LIBRARY__ */
+       while ((ch = getopt(ac, av, "cdks")) != -1) {
+#endif /* __GNU_LIBRARY__ */
+               switch (ch) {
+               case 'c':
+                       if (s_flag)
+                               usage();
+                       c_flag++;
+                       break;
+               case 'k':
+                       k_flag++;
+                       break;
+               case 's':
+                       if (c_flag)
+                               usage();
+                       s_flag++;
+                       break;
+               case 'd':
+                       if (d_flag)
+                               usage();
+                       d_flag++;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       ac -= optind;
+       av += optind;
+
+       if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
+               usage();
+
+       if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) {
+               shell = getenv("SHELL");
+               if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
+                       c_flag = 1;
+       }
+       if (k_flag) {
+               pidstr = getenv(SSH_AGENTPID_ENV_NAME);
+               if (pidstr == NULL) {
+                       fprintf(stderr, "%s not set, cannot kill agent\n",
+                           SSH_AGENTPID_ENV_NAME);
+                       exit(1);
+               }
+               pid = atoi(pidstr);
+               if (pid < 1) {
+                       fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
+                           SSH_AGENTPID_ENV_NAME, pidstr);
+                       exit(1);
+               }
+               if (kill(pid, SIGTERM) == -1) {
+                       perror("kill");
+                       exit(1);
+               }
+               format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
+               printf(format, SSH_AUTHSOCKET_ENV_NAME);
+               printf(format, SSH_AGENTPID_ENV_NAME);
+               printf("echo Agent pid %d killed;\n", pid);
+               exit(0);
+       }
+       parent_pid = getpid();
+
+       /* Create private directory for agent socket */
+       strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
+       if (mkdtemp(socket_dir) == NULL) {
+               perror("mkdtemp: private socket dir");
+               exit(1);
+       }
+       snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
+           parent_pid);
+
+       /*
+        * Create socket early so it will exist before command gets run from
+        * the parent.
+        */
+       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0) {
+               perror("socket");
+               cleanup_exit(1);
+       }
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
+#ifdef HAVE_CYGWIN
+       prev_mask = umask(0177);
+#endif
+       if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
+               perror("bind");
+#ifdef HAVE_CYGWIN
+               umask(prev_mask);
+#endif
+               cleanup_exit(1);
+       }
+#ifdef HAVE_CYGWIN
+       umask(prev_mask);
+#endif
+       if (listen(sock, 5) < 0) {
+               perror("listen");
+               cleanup_exit(1);
+       }
+
+       /*
+        * Fork, and have the parent execute the command, if any, or present
+        * the socket data.  The child continues as the authentication agent.
+        */
+       if (d_flag) {
+               log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
+               format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
+               printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+                   SSH_AUTHSOCKET_ENV_NAME);
+               printf("echo Agent pid %d;\n", parent_pid);
+               goto skip;
+       }
+       pid = fork();
+       if (pid == -1) {
+               perror("fork");
+               exit(1);
+       }
+       if (pid != 0) {         /* Parent - execute the given command. */
+               close(sock);
+               snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
+               if (ac == 0) {
+                       format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
+                       printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+                           SSH_AUTHSOCKET_ENV_NAME);
+                       printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
+                           SSH_AGENTPID_ENV_NAME);
+                       printf("echo Agent pid %d;\n", pid);
+                       exit(0);
+               }
+               if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
+                   setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
+                       perror("setenv");
+                       exit(1);
+               }
+               execvp(av[0], av);
+               perror(av[0]);
+               exit(1);
+       }
+
+       if (setsid() == -1) {
+               perror("setsid");
+               cleanup_exit(1);
+       }
+
+       (void)chdir("/");
+       close(0);
+       close(1);
+       close(2);
+
+#ifdef HAVE_SETRLIMIT
+       /* deny core dumps, since memory contains unencrypted private keys */
+       rlim.rlim_cur = rlim.rlim_max = 0;
+       if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
+               perror("setrlimit rlimit_core failed");
+               cleanup_exit(1);
+       }
+#endif
+
+skip:
+       if (atexit(cleanup_socket) < 0) {
+               perror("atexit");
+               cleanup_exit(1);
+       }
+       new_socket(AUTH_SOCKET, sock);
+       if (ac > 0) {
+               signal(SIGALRM, check_parent_exists);
+               alarm(10);
+       }
+       idtab_init();
+       if (!d_flag)
+               signal(SIGINT, SIG_IGN);
+       signal(SIGPIPE, SIG_IGN);
+       signal(SIGHUP, cleanup_handler);
+       signal(SIGTERM, cleanup_handler);
+       nalloc = 0;
+
+       while (1) {
+               prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
+               if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       exit(1);
+               }
+               after_select(readsetp, writesetp);
+       }
+       /* NOTREACHED */
+}
diff --git a/openssh/ssh-dss.c b/openssh/ssh-dss.c
new file mode 100644 (file)
index 0000000..9f3a287
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-dss.c,v 1.9 2001/11/07 22:10:28 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "compat.h"
+#include "log.h"
+#include "key.h"
+#include "ssh-dss.h"
+
+#define INTBLOB_LEN    20
+#define SIGBLOB_LEN    (2*INTBLOB_LEN)
+
+int
+ssh_dss_sign(
+    Key *key,
+    u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       DSA_SIG *sig;
+       EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+       u_char *digest, *ret, sigblob[SIGBLOB_LEN];
+       u_int rlen, slen, len, dlen;
+       Buffer b;
+
+       if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
+               error("ssh_dss_sign: no DSA key");
+               return -1;
+       }
+       dlen = evp_md->md_size;
+       digest = xmalloc(dlen);
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, NULL);
+
+       sig = DSA_do_sign(digest, dlen, key->dsa);
+
+       memset(digest, 0, dlen);
+       xfree(digest);
+       if (sig == NULL) {
+               error("ssh_dss_sign: sign failed");
+               return -1;
+       }
+
+       rlen = BN_num_bytes(sig->r);
+       slen = BN_num_bytes(sig->s);
+       if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
+               error("bad sig size %d %d", rlen, slen);
+               DSA_SIG_free(sig);
+               return -1;
+       }
+       memset(sigblob, 0, SIGBLOB_LEN);
+       BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
+       BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
+       DSA_SIG_free(sig);
+
+       if (datafellows & SSH_BUG_SIGBLOB) {
+               ret = xmalloc(SIGBLOB_LEN);
+               memcpy(ret, sigblob, SIGBLOB_LEN);
+               if (lenp != NULL)
+                       *lenp = SIGBLOB_LEN;
+               if (sigp != NULL)
+                       *sigp = ret;
+       } else {
+               /* ietf-drafts */
+               buffer_init(&b);
+               buffer_put_cstring(&b, "ssh-dss");
+               buffer_put_string(&b, sigblob, SIGBLOB_LEN);
+               len = buffer_len(&b);
+               ret = xmalloc(len);
+               memcpy(ret, buffer_ptr(&b), len);
+               buffer_free(&b);
+               if (lenp != NULL)
+                       *lenp = len;
+               if (sigp != NULL)
+                       *sigp = ret;
+       }
+       return 0;
+}
+int
+ssh_dss_verify(
+    Key *key,
+    u_char *signature, int signaturelen,
+    u_char *data, int datalen)
+{
+       DSA_SIG *sig;
+       EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+       u_char *digest, *sigblob;
+       u_int len, dlen;
+       int rlen, ret;
+       Buffer b;
+
+       if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
+               error("ssh_dss_verify: no DSA key");
+               return -1;
+       }
+
+       /* fetch signature */
+       if (datafellows & SSH_BUG_SIGBLOB) {
+               sigblob = signature;
+               len = signaturelen;
+       } else {
+               /* ietf-drafts */
+               char *ktype;
+               buffer_init(&b);
+               buffer_append(&b, signature, signaturelen);
+               ktype = buffer_get_string(&b, NULL);
+               if (strcmp("ssh-dss", ktype) != 0) {
+                       error("ssh_dss_verify: cannot handle type %s", ktype);
+                       buffer_free(&b);
+                       xfree(ktype);
+                       return -1;
+               }
+               xfree(ktype);
+               sigblob = buffer_get_string(&b, &len);
+               rlen = buffer_len(&b);
+               buffer_free(&b);
+               if(rlen != 0) {
+                       error("ssh_dss_verify: "
+                           "remaining bytes in signature %d", rlen);
+                       xfree(sigblob);
+                       return -1;
+               }
+       }
+
+       if (len != SIGBLOB_LEN) {
+               fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
+       }
+
+       /* parse signature */
+       sig = DSA_SIG_new();
+       sig->r = BN_new();
+       sig->s = BN_new();
+       BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
+       BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
+
+       if (!(datafellows & SSH_BUG_SIGBLOB)) {
+               memset(sigblob, 0, len);
+               xfree(sigblob);
+       }
+
+       /* sha1 the data */
+       dlen = evp_md->md_size;
+       digest = xmalloc(dlen);
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, NULL);
+
+       ret = DSA_do_verify(digest, dlen, sig, key->dsa);
+
+       memset(digest, 0, dlen);
+       xfree(digest);
+       DSA_SIG_free(sig);
+
+       debug("ssh_dss_verify: signature %s",
+           ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
+       return ret;
+}
diff --git a/openssh/ssh-dss.h b/openssh/ssh-dss.h
new file mode 100644 (file)
index 0000000..0613acb
--- /dev/null
@@ -0,0 +1,32 @@
+/*     $OpenBSD: ssh-dss.h,v 1.5 2001/06/26 17:27:25 markus Exp $      */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef DSA_H
+#define DSA_H
+
+int     ssh_dss_sign(Key *, u_char **, int *, u_char *, int);
+int     ssh_dss_verify(Key *, u_char *, int, u_char *, int);
+
+#endif
diff --git a/openssh/ssh-keygen.1 b/openssh/ssh-keygen.1
new file mode 100644 (file)
index 0000000..622cb5c
--- /dev/null
@@ -0,0 +1,296 @@
+.\"    $OpenBSD: ssh-keygen.1,v 1.50 2001/10/25 21:14:32 markus Exp $
+.\"
+.\"  -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\"                    All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose.  Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell.  All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd September 25, 1999
+.Dt SSH-KEYGEN 1
+.Os
+.Sh NAME
+.Nm ssh-keygen
+.Nd authentication key generation, management and conversion
+.Sh SYNOPSIS
+.Nm ssh-keygen
+.Op Fl q
+.Op Fl b Ar bits
+.Op Fl t Ar type
+.Op Fl N Ar new_passphrase
+.Op Fl C Ar comment
+.Op Fl f Ar output_keyfile
+.Nm ssh-keygen
+.Fl p
+.Op Fl P Ar old_passphrase
+.Op Fl N Ar new_passphrase
+.Op Fl f Ar keyfile
+.Nm ssh-keygen
+.Fl i
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl e
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl y
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl c
+.Op Fl P Ar passphrase
+.Op Fl C Ar comment
+.Op Fl f Ar keyfile
+.Nm ssh-keygen
+.Fl l
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl B
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl D Ar reader
+.Nm ssh-keygen
+.Fl U Ar reader
+.Op Fl f Ar input_keyfile
+.Sh DESCRIPTION
+.Nm
+generates, manages and converts authentication keys for
+.Xr ssh 1 .
+.Nm
+defaults to generating a RSA1 key for use by SSH protocol version 1.
+Specifying the
+.Fl t
+option instead creates a key for use by SSH protocol version 2.
+.Pp
+Normally each user wishing to use SSH
+with RSA or DSA authentication runs this once to create the authentication
+key in
+.Pa $HOME/.ssh/identity ,
+.Pa $HOME/.ssh/id_dsa
+or
+.Pa $HOME/.ssh/id_rsa .
+Additionally, the system administrator may use this to generate host keys,
+as seen in
+.Pa /etc/rc .
+.Pp
+Normally this program generates the key and asks for a file in which
+to store the private key.
+The public key is stored in a file with the same name but
+.Dq .pub
+appended.
+The program also asks for a passphrase.
+The passphrase may be empty to indicate no passphrase
+(host keys must have an empty passphrase), or it may be a string of
+arbitrary length.
+Good passphrases are 10-30 characters long and are
+not simple sentences or otherwise easily guessable (English
+prose has only 1-2 bits of entropy per character, and provides very bad
+passphrases).
+The passphrase can be changed later by using the
+.Fl p
+option.
+.Pp
+There is no way to recover a lost passphrase.
+If the passphrase is
+lost or forgotten, a new key must be generated and copied to the
+corresponding public key to other machines.
+.Pp
+For RSA1 keys,
+there is also a comment field in the key file that is only for
+convenience to the user to help identify the key.
+The comment can tell what the key is for, or whatever is useful.
+The comment is initialized to
+.Dq user@host
+when the key is created, but can be changed using the
+.Fl c
+option.
+.Pp
+After a key is generated, instructions below detail where the keys
+should be placed to be activated.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b Ar bits
+Specifies the number of bits in the key to create.
+Minimum is 512 bits.
+Generally 1024 bits is considered sufficient, and key sizes
+above that no longer improve security but make things slower.
+The default is 1024 bits.
+.It Fl c
+Requests changing the comment in the private and public key files.
+This operation is only supported for RSA1 keys.
+The program will prompt for the file containing the private keys, for
+the passphrase if the key has one, and for the new comment.
+.It Fl e
+This option will read a private or public OpenSSH key file and
+print the key in a
+.Sq SECSH Public Key File Format
+to stdout.
+This option allows exporting keys for use by several commercial
+SSH implementations.
+.It Fl f Ar filename
+Specifies the filename of the key file.
+.It Fl i
+This option will read an unencrypted private (or public) key file
+in SSH2-compatible format and print an OpenSSH compatible private
+(or public) key to stdout.
+.Nm
+also reads the
+.Sq SECSH Public Key File Format .
+This option allows importing keys from several commercial
+SSH implementations.
+.It Fl l
+Show fingerprint of specified public key file.
+Private RSA1 keys are also supported.
+For RSA and DSA keys
+.Nm
+tries to find the matching public key file and prints its fingerprint.
+.It Fl p
+Requests changing the passphrase of a private key file instead of
+creating a new private key.
+The program will prompt for the file
+containing the private key, for the old passphrase, and twice for the
+new passphrase.
+.It Fl q
+Silence
+.Nm ssh-keygen .
+Used by
+.Pa /etc/rc
+when creating a new key.
+.It Fl y
+This option will read a private
+OpenSSH format file and print an OpenSSH public key to stdout.
+.It Fl t Ar type
+Specifies the type of the key to create.
+The possible values are
+.Dq rsa1
+for protocol version 1 and
+.Dq rsa
+or
+.Dq dsa
+for protocol version 2.
+The default is
+.Dq rsa1 .
+.It Fl B
+Show the bubblebabble digest of specified private or public key file.
+.It Fl C Ar comment
+Provides the new comment.
+.It Fl D Ar reader
+Download the RSA public key stored in the smartcard in
+.Ar reader .
+.It Fl N Ar new_passphrase
+Provides the new passphrase.
+.It Fl P Ar passphrase
+Provides the (old) passphrase.
+.It Fl U Ar reader
+Upload an existing RSA private key into the smartcard in
+.Ar reader .
+.El
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $HOME/.ssh/identity
+Contains the protocol version 1 RSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file using 3DES.
+This file is not automatically accessed by
+.Nm
+but it is offered as the default file for the private key.
+.Xr ssh 1
+will read this file when a login attempt is made.
+.It Pa $HOME/.ssh/identity.pub
+Contains the protocol version 1 RSA public key for authentication.
+The contents of this file should be added to
+.Pa $HOME/.ssh/authorized_keys
+on all machines
+where the user wishes to log in using RSA authentication.
+There is no need to keep the contents of this file secret.
+.It Pa $HOME/.ssh/id_dsa
+Contains the protocol version 2 DSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file using 3DES.
+This file is not automatically accessed by
+.Nm
+but it is offered as the default file for the private key.
+.Xr ssh 1
+will read this file when a login attempt is made.
+.It Pa $HOME/.ssh/id_dsa.pub
+Contains the protocol version 2 DSA public key for authentication.
+The contents of this file should be added to
+.Pa $HOME/.ssh/authorized_keys
+on all machines
+where the user wishes to log in using public key authentication.
+There is no need to keep the contents of this file secret.
+.It Pa $HOME/.ssh/id_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file using 3DES.
+This file is not automatically accessed by
+.Nm
+but it is offered as the default file for the private key.
+.Xr ssh 1
+will read this file when a login attempt is made.
+.It Pa $HOME/.ssh/id_rsa.pub
+Contains the protocol version 2 RSA public key for authentication.
+The contents of this file should be added to
+.Pa $HOME/.ssh/authorized_keys
+on all machines
+where the user wishes to log in using public key authentication.
+There is no need to keep the contents of this file secret.
+.El
+.Sh AUTHORS
+OpenSSH is a derivative of the original and free
+ssh 1.2.12 release by Tatu Ylonen.
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
+Theo de Raadt and Dug Song
+removed many bugs, re-added newer features and
+created OpenSSH.
+Markus Friedl contributed the support for SSH
+protocol versions 1.5 and 2.0.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr sshd 8
+.Rs
+.%A J. Galbraith
+.%A R. Thayer
+.%T "SECSH Public Key File Format"
+.%N draft-ietf-secsh-publickeyfile-01.txt
+.%D March 2001
+.%O work in progress material
+.Re
diff --git a/openssh/ssh-keygen.c b/openssh/ssh-keygen.c
new file mode 100644 (file)
index 0000000..6d50997
--- /dev/null
@@ -0,0 +1,1085 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Identity and host key generation and maintenance.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-keygen.c,v 1.83 2001/10/25 21:14:32 markus Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "rsa.h"
+#include "authfile.h"
+#include "uuencode.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "pathnames.h"
+#include "log.h"
+#include "readpass.h"
+
+#ifdef SMARTCARD
+#include <sectok.h>
+#include <openssl/engine.h>
+#include "scard.h"
+#endif
+
+/* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
+int bits = 1024;
+
+/*
+ * Flag indicating that we just want to change the passphrase.  This can be
+ * set on the command line.
+ */
+int change_passphrase = 0;
+
+/*
+ * Flag indicating that we just want to change the comment.  This can be set
+ * on the command line.
+ */
+int change_comment = 0;
+
+int quiet = 0;
+
+/* Flag indicating that we just want to see the key fingerprint */
+int print_fingerprint = 0;
+int print_bubblebabble = 0;
+
+/* The identity file name, given on the command line or entered by the user. */
+char identity_file[1024];
+int have_identity = 0;
+
+/* This is set to the passphrase if given on the command line. */
+char *identity_passphrase = NULL;
+
+/* This is set to the new passphrase if given on the command line. */
+char *identity_new_passphrase = NULL;
+
+/* This is set to the new comment if given on the command line. */
+char *identity_comment = NULL;
+
+/* Dump public key file in format used by real and the original SSH 2 */
+int convert_to_ssh2 = 0;
+int convert_from_ssh2 = 0;
+int print_public = 0;
+
+/* default to RSA for SSH-1 */
+char *key_type_name = "rsa1";
+
+/* argv0 */
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+char hostname[MAXHOSTNAMELEN];
+
+static void
+ask_filename(struct passwd *pw, const char *prompt)
+{
+       char buf[1024];
+       char *name = NULL;
+
+       switch (key_type_from_name(key_type_name)) {
+       case KEY_RSA1:
+               name = _PATH_SSH_CLIENT_IDENTITY;
+               break;
+       case KEY_DSA:
+               name = _PATH_SSH_CLIENT_ID_DSA;
+               break;
+       case KEY_RSA:
+               name = _PATH_SSH_CLIENT_ID_RSA;
+               break;
+       default:
+               fprintf(stderr, "bad key type");
+               exit(1);
+               break;
+       }
+       snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
+       fprintf(stderr, "%s (%s): ", prompt, identity_file);
+       fflush(stderr);
+       if (fgets(buf, sizeof(buf), stdin) == NULL)
+               exit(1);
+       if (strchr(buf, '\n'))
+               *strchr(buf, '\n') = 0;
+       if (strcmp(buf, "") != 0)
+               strlcpy(identity_file, buf, sizeof(identity_file));
+       have_identity = 1;
+}
+
+static Key *
+load_identity(char *filename)
+{
+       char *pass;
+       Key *prv;
+
+       prv = key_load_private(filename, "", NULL);
+       if (prv == NULL) {
+               if (identity_passphrase)
+                       pass = xstrdup(identity_passphrase);
+               else
+                       pass = read_passphrase("Enter passphrase: ",
+                           RP_ALLOW_STDIN);
+               prv = key_load_private(filename, pass, NULL);
+               memset(pass, 0, strlen(pass));
+               xfree(pass);
+       }
+       return prv;
+}
+
+#define SSH_COM_PUBLIC_BEGIN           "---- BEGIN SSH2 PUBLIC KEY ----"
+#define SSH_COM_PUBLIC_END             "---- END SSH2 PUBLIC KEY ----"
+#define SSH_COM_PRIVATE_BEGIN          "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
+#define        SSH_COM_PRIVATE_KEY_MAGIC       0x3f6ff9eb
+
+static void
+do_convert_to_ssh2(struct passwd *pw)
+{
+       Key *k;
+       int len;
+       u_char *blob;
+       struct stat st;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       if ((k = key_load_public(identity_file, NULL)) == NULL) {
+               if ((k = load_identity(identity_file)) == NULL) {
+                       fprintf(stderr, "load failed\n");
+                       exit(1);
+               }
+       }
+       if (key_to_blob(k, &blob, &len) <= 0) {
+               fprintf(stderr, "key_to_blob failed\n");
+               exit(1);
+       }
+       fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
+       fprintf(stdout,
+           "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
+           key_size(k), key_type(k),
+           pw->pw_name, hostname);
+       dump_base64(stdout, blob, len);
+       fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
+       key_free(k);
+       xfree(blob);
+       exit(0);
+}
+
+static void
+buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
+{
+       int bits = buffer_get_int(b);
+       int bytes = (bits + 7) / 8;
+
+       if (buffer_len(b) < bytes)
+               fatal("buffer_get_bignum_bits: input buffer too small: "
+                   "need %d have %d", bytes, buffer_len(b));
+       BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
+       buffer_consume(b, bytes);
+}
+
+static Key *
+do_convert_private_ssh2_from_blob(u_char *blob, int blen)
+{
+       Buffer b;
+       Key *key = NULL;
+       char *type, *cipher;
+       u_char *sig, data[] = "abcde12345";
+       int magic, rlen, ktype, i1, i2, i3, i4;
+       u_int slen;
+       u_long e;
+
+       buffer_init(&b);
+       buffer_append(&b, blob, blen);
+
+       magic  = buffer_get_int(&b);
+       if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
+               error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
+               buffer_free(&b);
+               return NULL;
+       }
+       i1 = buffer_get_int(&b);
+       type   = buffer_get_string(&b, NULL);
+       cipher = buffer_get_string(&b, NULL);
+       i2 = buffer_get_int(&b);
+       i3 = buffer_get_int(&b);
+       i4 = buffer_get_int(&b);
+       debug("ignore (%d %d %d %d)", i1,i2,i3,i4);
+       if (strcmp(cipher, "none") != 0) {
+               error("unsupported cipher %s", cipher);
+               xfree(cipher);
+               buffer_free(&b);
+               xfree(type);
+               return NULL;
+       }
+       xfree(cipher);
+
+       if (strstr(type, "dsa")) {
+               ktype = KEY_DSA;
+       } else if (strstr(type, "rsa")) {
+               ktype = KEY_RSA;
+       } else {
+               xfree(type);
+               return NULL;
+       }
+       key = key_new_private(ktype);
+       xfree(type);
+
+       switch (key->type) {
+       case KEY_DSA:
+               buffer_get_bignum_bits(&b, key->dsa->p);
+               buffer_get_bignum_bits(&b, key->dsa->g);
+               buffer_get_bignum_bits(&b, key->dsa->q);
+               buffer_get_bignum_bits(&b, key->dsa->pub_key);
+               buffer_get_bignum_bits(&b, key->dsa->priv_key);
+               break;
+       case KEY_RSA:
+               e  = buffer_get_char(&b);
+               debug("e %lx", e);
+               if (e < 30) {
+                       e <<= 8;
+                       e += buffer_get_char(&b);
+                       debug("e %lx", e);
+                       e <<= 8;
+                       e += buffer_get_char(&b);
+                       debug("e %lx", e);
+               }
+               if (!BN_set_word(key->rsa->e, e)) {
+                       buffer_free(&b);
+                       key_free(key);
+                       return NULL;
+               }
+               buffer_get_bignum_bits(&b, key->rsa->d);
+               buffer_get_bignum_bits(&b, key->rsa->n);
+               buffer_get_bignum_bits(&b, key->rsa->iqmp);
+               buffer_get_bignum_bits(&b, key->rsa->q);
+               buffer_get_bignum_bits(&b, key->rsa->p);
+               rsa_generate_additional_parameters(key->rsa);
+               break;
+       }
+       rlen = buffer_len(&b);
+       if(rlen != 0)
+               error("do_convert_private_ssh2_from_blob: "
+                   "remaining bytes in key blob %d", rlen);
+       buffer_free(&b);
+
+       /* try the key */
+       key_sign(key, &sig, &slen, data, sizeof(data));
+       key_verify(key, sig, slen, data, sizeof(data));
+       xfree(sig);
+       return key;
+}
+
+static void
+do_convert_from_ssh2(struct passwd *pw)
+{
+       Key *k;
+       int blen;
+       char line[1024], *p;
+       u_char blob[8096];
+       char encoded[8096];
+       struct stat st;
+       int escaped = 0, private = 0, ok;
+       FILE *fp;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       fp = fopen(identity_file, "r");
+       if (fp == NULL) {
+               perror(identity_file);
+               exit(1);
+       }
+       encoded[0] = '\0';
+       while (fgets(line, sizeof(line), fp)) {
+               if (!(p = strchr(line, '\n'))) {
+                       fprintf(stderr, "input line too long.\n");
+                       exit(1);
+               }
+               if (p > line && p[-1] == '\\')
+                       escaped++;
+               if (strncmp(line, "----", 4) == 0 ||
+                   strstr(line, ": ") != NULL) {
+                       if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
+                               private = 1;
+                       if (strstr(line, " END ") != NULL) {
+                               break;
+                       }
+                       /* fprintf(stderr, "ignore: %s", line); */
+                       continue;
+               }
+               if (escaped) {
+                       escaped--;
+                       /* fprintf(stderr, "escaped: %s", line); */
+                       continue;
+               }
+               *p = '\0';
+               strlcat(encoded, line, sizeof(encoded));
+       }
+       blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
+       if (blen < 0) {
+               fprintf(stderr, "uudecode failed.\n");
+               exit(1);
+       }
+       k = private ?
+           do_convert_private_ssh2_from_blob(blob, blen) :
+           key_from_blob(blob, blen);
+       if (k == NULL) {
+               fprintf(stderr, "decode blob failed.\n");
+               exit(1);
+       }
+       ok = private ?
+           (k->type == KEY_DSA ?
+                PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
+                PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
+           key_write(k, stdout);
+       if (!ok) {
+               fprintf(stderr, "key write failed");
+               exit(1);
+       }
+       key_free(k);
+       fprintf(stdout, "\n");
+       fclose(fp);
+       exit(0);
+}
+
+static void
+do_print_public(struct passwd *pw)
+{
+       Key *prv;
+       struct stat st;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       prv = load_identity(identity_file);
+       if (prv == NULL) {
+               fprintf(stderr, "load failed\n");
+               exit(1);
+       }
+       if (!key_write(prv, stdout))
+               fprintf(stderr, "key_write failed");
+       key_free(prv);
+       fprintf(stdout, "\n");
+       exit(0);
+}
+
+#ifdef SMARTCARD
+#define NUM_RSA_KEY_ELEMENTS 5+1
+#define COPY_RSA_KEY(x, i) \
+       do { \
+               len = BN_num_bytes(prv->rsa->x); \
+               elements[i] = xmalloc(len); \
+               debug("#bytes %d", len); \
+               if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \
+                       goto done; \
+       } while(0)
+
+static int
+get_AUT0(char *aut0)
+{
+       EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+       char *pass;
+
+       pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
+       if (pass == NULL)
+               return -1;
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, pass, strlen(pass));
+       EVP_DigestFinal(&md, aut0, NULL);
+       memset(pass, 0, strlen(pass));
+       xfree(pass);
+       return 0;
+}
+
+static void
+do_upload(struct passwd *pw, const char *sc_reader_id)
+{
+       Key *prv = NULL;
+       struct stat st;
+       u_char *elements[NUM_RSA_KEY_ELEMENTS];
+       u_char key_fid[2];
+       u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
+       u_char AUT0[EVP_MAX_MD_SIZE];
+       int len, status = 1, i, fd = -1, ret;
+       int sw = 0, cla = 0x00;
+
+       for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
+               elements[i] = NULL;
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               goto done;
+       }
+       prv = load_identity(identity_file);
+       if (prv == NULL) {
+               error("load failed");
+               goto done;
+       }
+       COPY_RSA_KEY(q, 0);
+       COPY_RSA_KEY(p, 1);
+       COPY_RSA_KEY(iqmp, 2);
+       COPY_RSA_KEY(dmq1, 3);
+       COPY_RSA_KEY(dmp1, 4);
+       COPY_RSA_KEY(n, 5);
+       len = BN_num_bytes(prv->rsa->n);
+       fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
+       if (fd < 0) {
+               error("sectok_open failed: %s", sectok_get_sw(sw));
+               goto done;
+       }
+       if (! sectok_cardpresent(fd)) {
+               error("smartcard in reader %s not present",
+                   sc_reader_id);
+               goto done;
+       }
+       ret = sectok_reset(fd, 0, NULL, &sw);
+       if (ret <= 0) {
+               error("sectok_reset failed: %s", sectok_get_sw(sw));
+               goto done;
+       }
+       if ((cla = cyberflex_inq_class(fd)) < 0) {
+               error("cyberflex_inq_class failed");
+               goto done;
+       }
+       memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0));
+       if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
+               if (get_AUT0(AUT0) < 0 ||
+                   cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
+                       error("cyberflex_verify_AUT0 failed");
+                       goto done;
+               }
+       }
+       key_fid[0] = 0x00;
+       key_fid[1] = 0x12;
+       if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements,
+           &sw) < 0) {
+               error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw));
+               goto done;
+       }
+       if (!sectok_swOK(sw))
+               goto done;
+       log("cyberflex_load_rsa_priv done");
+       key_fid[0] = 0x73;
+       key_fid[1] = 0x68;
+       if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5],
+           &sw) < 0) {
+               error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw));
+               goto done;
+       }
+       if (!sectok_swOK(sw))
+               goto done;
+       log("cyberflex_load_rsa_pub done");
+       status = 0;
+       log("loading key done");
+done:
+
+       memset(elements[0], '\0', BN_num_bytes(prv->rsa->q));
+       memset(elements[1], '\0', BN_num_bytes(prv->rsa->p));
+       memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp));
+       memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1));
+       memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1));
+       memset(elements[5], '\0', BN_num_bytes(prv->rsa->n));
+
+       if (prv)
+               key_free(prv);
+       for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
+               if (elements[i])
+                       xfree(elements[i]);
+       if (fd != -1)
+               sectok_close(fd);
+       exit(status);
+}
+
+static void
+do_download(struct passwd *pw, const char *sc_reader_id)
+{
+       Key *pub = NULL;
+
+       pub = sc_get_key(sc_reader_id);
+       if (pub == NULL)
+               fatal("cannot read public key from smartcard");
+       key_write(pub, stdout);
+       key_free(pub);
+       fprintf(stdout, "\n");
+       exit(0);
+}
+#endif /* SMARTCARD */
+
+static void
+do_fingerprint(struct passwd *pw)
+{
+       FILE *f;
+       Key *public;
+       char *comment = NULL, *cp, *ep, line[16*1024], *fp;
+       int i, skip = 0, num = 1, invalid = 1, rep, fptype;
+       struct stat st;
+
+       fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+       rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       public = key_load_public(identity_file, &comment);
+       if (public != NULL) {
+               fp = key_fingerprint(public, fptype, rep);
+               printf("%d %s %s\n", key_size(public), fp, comment);
+               key_free(public);
+               xfree(comment);
+               xfree(fp);
+               exit(0);
+       }
+       if (comment)
+               xfree(comment);
+
+       f = fopen(identity_file, "r");
+       if (f != NULL) {
+               while (fgets(line, sizeof(line), f)) {
+                       i = strlen(line) - 1;
+                       if (line[i] != '\n') {
+                               error("line %d too long: %.40s...", num, line);
+                               skip = 1;
+                               continue;
+                       }
+                       num++;
+                       if (skip) {
+                               skip = 0;
+                               continue;
+                       }
+                       line[i] = '\0';
+
+                       /* Skip leading whitespace, empty and comment lines. */
+                       for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+                               ;
+                       if (!*cp || *cp == '\n' || *cp == '#')
+                               continue ;
+                       i = strtol(cp, &ep, 10);
+                       if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
+                               int quoted = 0;
+                               comment = cp;
+                               for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+                                       if (*cp == '\\' && cp[1] == '"')
+                                               cp++;   /* Skip both */
+                                       else if (*cp == '"')
+                                               quoted = !quoted;
+                               }
+                               if (!*cp)
+                                       continue;
+                               *cp++ = '\0';
+                       }
+                       ep = cp;
+                       public = key_new(KEY_RSA1);
+                       if (key_read(public, &cp) != 1) {
+                               cp = ep;
+                               key_free(public);
+                               public = key_new(KEY_UNSPEC);
+                               if (key_read(public, &cp) != 1) {
+                                       key_free(public);
+                                       continue;
+                               }
+                       }
+                       comment = *cp ? cp : comment;
+                       fp = key_fingerprint(public, fptype, rep);
+                       printf("%d %s %s\n", key_size(public), fp,
+                           comment ? comment : "no comment");
+                       xfree(fp);
+                       key_free(public);
+                       invalid = 0;
+               }
+               fclose(f);
+       }
+       if (invalid) {
+               printf("%s is not a public key file.\n", identity_file);
+               exit(1);
+       }
+       exit(0);
+}
+
+/*
+ * Perform changing a passphrase.  The argument is the passwd structure
+ * for the current user.
+ */
+static void
+do_change_passphrase(struct passwd *pw)
+{
+       char *comment;
+       char *old_passphrase, *passphrase1, *passphrase2;
+       struct stat st;
+       Key *private;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       /* Try to load the file with empty passphrase. */
+       private = key_load_private(identity_file, "", &comment);
+       if (private == NULL) {
+               if (identity_passphrase)
+                       old_passphrase = xstrdup(identity_passphrase);
+               else
+                       old_passphrase =
+                           read_passphrase("Enter old passphrase: ",
+                           RP_ALLOW_STDIN);
+               private = key_load_private(identity_file, old_passphrase,
+                   &comment);
+               memset(old_passphrase, 0, strlen(old_passphrase));
+               xfree(old_passphrase);
+               if (private == NULL) {
+                       printf("Bad passphrase.\n");
+                       exit(1);
+               }
+       }
+       printf("Key has comment '%s'\n", comment);
+
+       /* Ask the new passphrase (twice). */
+       if (identity_new_passphrase) {
+               passphrase1 = xstrdup(identity_new_passphrase);
+               passphrase2 = NULL;
+       } else {
+               passphrase1 =
+                       read_passphrase("Enter new passphrase (empty for no "
+                           "passphrase): ", RP_ALLOW_STDIN);
+               passphrase2 = read_passphrase("Enter same passphrase again: ",
+                    RP_ALLOW_STDIN);
+
+               /* Verify that they are the same. */
+               if (strcmp(passphrase1, passphrase2) != 0) {
+                       memset(passphrase1, 0, strlen(passphrase1));
+                       memset(passphrase2, 0, strlen(passphrase2));
+                       xfree(passphrase1);
+                       xfree(passphrase2);
+                       printf("Pass phrases do not match.  Try again.\n");
+                       exit(1);
+               }
+               /* Destroy the other copy. */
+               memset(passphrase2, 0, strlen(passphrase2));
+               xfree(passphrase2);
+       }
+
+       /* Save the file using the new passphrase. */
+       if (!key_save_private(private, identity_file, passphrase1, comment)) {
+               printf("Saving the key failed: %s.\n", identity_file);
+               memset(passphrase1, 0, strlen(passphrase1));
+               xfree(passphrase1);
+               key_free(private);
+               xfree(comment);
+               exit(1);
+       }
+       /* Destroy the passphrase and the copy of the key in memory. */
+       memset(passphrase1, 0, strlen(passphrase1));
+       xfree(passphrase1);
+       key_free(private);               /* Destroys contents */
+       xfree(comment);
+
+       printf("Your identification has been saved with the new passphrase.\n");
+       exit(0);
+}
+
+/*
+ * Change the comment of a private key file.
+ */
+static void
+do_change_comment(struct passwd *pw)
+{
+       char new_comment[1024], *comment, *passphrase;
+       Key *private;
+       Key *public;
+       struct stat st;
+       FILE *f;
+       int fd;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0) {
+               perror(identity_file);
+               exit(1);
+       }
+       private = key_load_private(identity_file, "", &comment);
+       if (private == NULL) {
+               if (identity_passphrase)
+                       passphrase = xstrdup(identity_passphrase);
+               else if (identity_new_passphrase)
+                       passphrase = xstrdup(identity_new_passphrase);
+               else
+                       passphrase = read_passphrase("Enter passphrase: ",
+                           RP_ALLOW_STDIN);
+               /* Try to load using the passphrase. */
+               private = key_load_private(identity_file, passphrase, &comment);
+               if (private == NULL) {
+                       memset(passphrase, 0, strlen(passphrase));
+                       xfree(passphrase);
+                       printf("Bad passphrase.\n");
+                       exit(1);
+               }
+       } else {
+               passphrase = xstrdup("");
+       }
+       if (private->type != KEY_RSA1) {
+               fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
+               key_free(private);
+               exit(1);
+       }       
+       printf("Key now has comment '%s'\n", comment);
+
+       if (identity_comment) {
+               strlcpy(new_comment, identity_comment, sizeof(new_comment));
+       } else {
+               printf("Enter new comment: ");
+               fflush(stdout);
+               if (!fgets(new_comment, sizeof(new_comment), stdin)) {
+                       memset(passphrase, 0, strlen(passphrase));
+                       key_free(private);
+                       exit(1);
+               }
+               if (strchr(new_comment, '\n'))
+                       *strchr(new_comment, '\n') = 0;
+       }
+
+       /* Save the file using the new passphrase. */
+       if (!key_save_private(private, identity_file, passphrase, new_comment)) {
+               printf("Saving the key failed: %s.\n", identity_file);
+               memset(passphrase, 0, strlen(passphrase));
+               xfree(passphrase);
+               key_free(private);
+               xfree(comment);
+               exit(1);
+       }
+       memset(passphrase, 0, strlen(passphrase));
+       xfree(passphrase);
+       public = key_from_private(private);
+       key_free(private);
+
+       strlcat(identity_file, ".pub", sizeof(identity_file));
+       fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+       if (fd == -1) {
+               printf("Could not save your public key in %s\n", identity_file);
+               exit(1);
+       }
+       f = fdopen(fd, "w");
+       if (f == NULL) {
+               printf("fdopen %s failed", identity_file);
+               exit(1);
+       }
+       if (!key_write(public, f))
+               fprintf(stderr, "write key failed");
+       key_free(public);
+       fprintf(f, " %s\n", new_comment);
+       fclose(f);
+
+       xfree(comment);
+
+       printf("The comment in your key file has been changed.\n");
+       exit(0);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: %s [options]\n", __progname);
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
+       fprintf(stderr, "  -c          Change comment in private and public key files.\n");
+       fprintf(stderr, "  -e          Convert OpenSSH to IETF SECSH key file.\n");
+       fprintf(stderr, "  -f filename Filename of the key file.\n");
+       fprintf(stderr, "  -i          Convert IETF SECSH to OpenSSH key file.\n");
+       fprintf(stderr, "  -l          Show fingerprint of key file.\n");
+       fprintf(stderr, "  -p          Change passphrase of private key file.\n");
+       fprintf(stderr, "  -q          Quiet.\n");
+       fprintf(stderr, "  -y          Read private key file and print public key.\n");
+       fprintf(stderr, "  -t type     Specify type of key to create.\n");
+       fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
+       fprintf(stderr, "  -C comment  Provide new comment.\n");
+       fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
+       fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
+#ifdef SMARTCARD
+       fprintf(stderr, "  -D reader   Download public key from smartcard.\n");
+       fprintf(stderr, "  -U reader   Upload private key to smartcard.\n");
+#endif /* SMARTCARD */
+
+       exit(1);
+}
+
+/*
+ * Main program for key management.
+ */
+int
+main(int ac, char **av)
+{
+       char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
+       char *reader_id = NULL;
+       Key *private, *public;
+       struct passwd *pw;
+       struct stat st;
+       int opt, type, fd, download = 0;
+       FILE *f;
+
+       extern int optind;
+       extern char *optarg;
+
+       __progname = get_progname(av[0]);
+       init_rng();
+       seed_rng();
+
+       SSLeay_add_all_algorithms();
+
+       /* we need this for the home * directory.  */
+       pw = getpwuid(getuid());
+       if (!pw) {
+               printf("You don't exist, go away!\n");
+               exit(1);
+       }
+       if (gethostname(hostname, sizeof(hostname)) < 0) {
+               perror("gethostname");
+               exit(1);
+       }
+
+       while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:U:D:P:N:C:")) != -1) {
+               switch (opt) {
+               case 'b':
+                       bits = atoi(optarg);
+                       if (bits < 512 || bits > 32768) {
+                               printf("Bits has bad value.\n");
+                               exit(1);
+                       }
+                       break;
+               case 'l':
+                       print_fingerprint = 1;
+                       break;
+               case 'B':
+                       print_bubblebabble = 1;
+                       break;
+               case 'p':
+                       change_passphrase = 1;
+                       break;
+               case 'c':
+                       change_comment = 1;
+                       break;
+               case 'f':
+                       strlcpy(identity_file, optarg, sizeof(identity_file));
+                       have_identity = 1;
+                       break;
+               case 'P':
+                       identity_passphrase = optarg;
+                       break;
+               case 'N':
+                       identity_new_passphrase = optarg;
+                       break;
+               case 'C':
+                       identity_comment = optarg;
+                       break;
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'R':
+                       /* unused */
+                       exit(0);
+                       break;
+               case 'e':
+               case 'x':
+                       /* export key */
+                       convert_to_ssh2 = 1;
+                       break;
+               case 'i':
+               case 'X':
+                       /* import key */
+                       convert_from_ssh2 = 1;
+                       break;
+               case 'y':
+                       print_public = 1;
+                       break;
+               case 'd':
+                       key_type_name = "dsa";
+                       break;
+               case 't':
+                       key_type_name = optarg;
+                       break;
+               case 'D':
+                       download = 1;
+               case 'U':
+                       reader_id = optarg;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       }
+       if (optind < ac) {
+               printf("Too many arguments.\n");
+               usage();
+       }
+       if (change_passphrase && change_comment) {
+               printf("Can only have one of -p and -c.\n");
+               usage();
+       }
+       if (print_fingerprint || print_bubblebabble)
+               do_fingerprint(pw);
+       if (change_passphrase)
+               do_change_passphrase(pw);
+       if (change_comment)
+               do_change_comment(pw);
+       if (convert_to_ssh2)
+               do_convert_to_ssh2(pw);
+       if (convert_from_ssh2)
+               do_convert_from_ssh2(pw);
+       if (print_public)
+               do_print_public(pw);
+       if (reader_id != NULL) {
+#ifdef SMARTCARD
+               if (download)
+                       do_download(pw, reader_id);
+               else
+                       do_upload(pw, reader_id);
+#else /* SMARTCARD */
+               fatal("no support for smartcards.");
+#endif /* SMARTCARD */
+       }
+
+       arc4random_stir();
+
+       type = key_type_from_name(key_type_name);
+       if (type == KEY_UNSPEC) {
+               fprintf(stderr, "unknown key type %s\n", key_type_name);
+               exit(1);
+       }
+       if (!quiet)
+               printf("Generating public/private %s key pair.\n", key_type_name);
+       private = key_generate(type, bits);
+       if (private == NULL) {
+               fprintf(stderr, "key_generate failed");
+               exit(1);
+       }
+       public  = key_from_private(private);
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which to save the key");
+
+       /* Create ~/.ssh directory if it doesn\'t already exist. */
+       snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
+       if (strstr(identity_file, dotsshdir) != NULL &&
+           stat(dotsshdir, &st) < 0) {
+               if (mkdir(dotsshdir, 0700) < 0)
+                       error("Could not create directory '%s'.", dotsshdir);
+               else if (!quiet)
+                       printf("Created directory '%s'.\n", dotsshdir);
+       }
+       /* If the file already exists, ask the user to confirm. */
+       if (stat(identity_file, &st) >= 0) {
+               char yesno[3];
+               printf("%s already exists.\n", identity_file);
+               printf("Overwrite (y/n)? ");
+               fflush(stdout);
+               if (fgets(yesno, sizeof(yesno), stdin) == NULL)
+                       exit(1);
+               if (yesno[0] != 'y' && yesno[0] != 'Y')
+                       exit(1);
+       }
+       /* Ask for a passphrase (twice). */
+       if (identity_passphrase)
+               passphrase1 = xstrdup(identity_passphrase);
+       else if (identity_new_passphrase)
+               passphrase1 = xstrdup(identity_new_passphrase);
+       else {
+passphrase_again:
+               passphrase1 =
+                       read_passphrase("Enter passphrase (empty for no "
+                           "passphrase): ", RP_ALLOW_STDIN);
+               passphrase2 = read_passphrase("Enter same passphrase again: ",
+                   RP_ALLOW_STDIN);
+               if (strcmp(passphrase1, passphrase2) != 0) {
+                       /*
+                        * The passphrases do not match.  Clear them and
+                        * retry.
+                        */
+                       memset(passphrase1, 0, strlen(passphrase1));
+                       memset(passphrase2, 0, strlen(passphrase2));
+                       xfree(passphrase1);
+                       xfree(passphrase2);
+                       printf("Passphrases do not match.  Try again.\n");
+                       goto passphrase_again;
+               }
+               /* Clear the other copy of the passphrase. */
+               memset(passphrase2, 0, strlen(passphrase2));
+               xfree(passphrase2);
+       }
+
+       if (identity_comment) {
+               strlcpy(comment, identity_comment, sizeof(comment));
+       } else {
+               /* Create default commend field for the passphrase. */
+               snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
+       }
+
+       /* Save the key with the given passphrase and comment. */
+       if (!key_save_private(private, identity_file, passphrase1, comment)) {
+               printf("Saving the key failed: %s.\n", identity_file);
+               memset(passphrase1, 0, strlen(passphrase1));
+               xfree(passphrase1);
+               exit(1);
+       }
+       /* Clear the passphrase. */
+       memset(passphrase1, 0, strlen(passphrase1));
+       xfree(passphrase1);
+
+       /* Clear the private key and the random number generator. */
+       key_free(private);
+       arc4random_stir();
+
+       if (!quiet)
+               printf("Your identification has been saved in %s.\n", identity_file);
+
+       strlcat(identity_file, ".pub", sizeof(identity_file));
+       fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+       if (fd == -1) {
+               printf("Could not save your public key in %s\n", identity_file);
+               exit(1);
+       }
+       f = fdopen(fd, "w");
+       if (f == NULL) {
+               printf("fdopen %s failed", identity_file);
+               exit(1);
+       }
+       if (!key_write(public, f))
+               fprintf(stderr, "write key failed");
+       fprintf(f, " %s\n", comment);
+       fclose(f);
+
+       if (!quiet) {
+               char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
+               printf("Your public key has been saved in %s.\n",
+                   identity_file);
+               printf("The key fingerprint is:\n");
+               printf("%s %s\n", fp, comment);
+               xfree(fp);
+       }
+
+       key_free(public);
+       exit(0);
+}
diff --git a/openssh/ssh-keyscan.1 b/openssh/ssh-keyscan.1
new file mode 100644 (file)
index 0000000..17f7340
--- /dev/null
@@ -0,0 +1,154 @@
+.\"    $OpenBSD: ssh-keyscan.1,v 1.12 2001/09/05 06:23:07 deraadt Exp $
+.\"
+.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
+.\"
+.\" Modification and redistribution in source and binary forms is
+.\" permitted provided that due credit is given to the author and the
+.\" OpenBSD project by leaving this copyright notice intact.
+.\"
+.Dd January 1, 1996
+.Dt SSH-KEYSCAN 1
+.Os
+.Sh NAME
+.Nm ssh-keyscan
+.Nd gather ssh public keys
+.Sh SYNOPSIS
+.Nm ssh-keyscan
+.Op Fl v46
+.Op Fl p Ar port
+.Op Fl T Ar timeout
+.Op Fl t Ar type
+.Op Fl f Ar file
+.Op Ar host | addrlist namelist
+.Op Ar ...
+.Sh DESCRIPTION
+.Nm
+is a utility for gathering the public ssh host keys of a number of
+hosts.  It was designed to aid in building and verifying
+.Pa ssh_known_hosts
+files.
+.Nm
+provides a minimal interface suitable for use by shell and perl
+scripts.
+.Pp
+.Nm
+uses non-blocking socket I/O to contact as many hosts as possible in
+parallel, so it is very efficient.  The keys from a domain of 1,000
+hosts can be collected in tens of seconds, even when some of those
+hosts are down or do not run ssh.  For scanning, one does not need
+login access to the machines that are being scanned, nor does the
+scanning process involve any encryption.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl p Ar port
+Port to connect to on the remote host.
+.It Fl T Ar timeout
+Set the timeout for connection attempts.  If
+.Pa timeout
+seconds have elapsed since a connection was initiated to a host or since the
+last time anything was read from that host, then the connection is
+closed and the host in question considered unavailable.  Default is 5
+seconds.
+.It Fl t Ar type
+Specifies the type of the key to fetch from the scanned hosts.
+The possible values are
+.Dq rsa1
+for protocol version 1 and
+.Dq rsa
+or
+.Dq dsa
+for protocol version 2.
+Multiple values may be specified by separating them with commas.
+The default is
+.Dq rsa1 .
+.It Fl f Ar filename
+Read hosts or
+.Pa addrlist namelist
+pairs from this file, one per line.
+If
+.Pa -
+is supplied instead of a filename,
+.Nm
+will read hosts or
+.Pa addrlist namelist
+pairs from the standard input.
+.It Fl v
+Verbose mode.
+Causes
+.Nm
+to print debugging messages about its progress.
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.El
+.Sh SECURITY
+If a ssh_known_hosts file is constructed using
+.Nm
+without verifying the keys, users will be vulnerable to
+.I man in the middle
+attacks.
+On the other hand, if the security model allows such a risk,
+.Nm
+can help in the detection of tampered keyfiles or man in the middle
+attacks which have begun after the ssh_known_hosts file was created.
+.Sh EXAMPLES
+.Pp
+Print the
+.Pa rsa1
+host key for machine
+.Pa hostname :
+.Bd -literal
+ssh-keyscan hostname
+.Ed
+.Pp
+Find all hosts from the file
+.Pa ssh_hosts
+which have new or different keys from those in the sorted file
+.Pa ssh_known_hosts :
+.Bd -literal
+ssh-keyscan -t rsa,dsa -f ssh_hosts | \e\ 
+       sort -u - ssh_known_hosts | diff ssh_known_hosts -
+.Ed
+.Sh FILES
+.Pa Input format:
+.Bd -literal
+1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
+.Ed
+.Pp
+.Pa Output format for rsa1 keys:
+.Bd -literal
+host-or-namelist bits exponent modulus
+.Ed
+.Pp
+.Pa Output format for rsa and dsa keys:
+.Bd -literal
+host-or-namelist keytype base64-encoded-key
+.Ed
+.Pp
+Where
+.Pa keytype
+is either
+.Dq ssh-rsa
+or
+.Dq ssh-dsa .
+.Pp
+.Pa /etc/ssh_known_hosts
+.Sh BUGS
+It generates "Connection closed by remote host" messages on the consoles
+of all the machines it scans if the server is older than version 2.9.
+This is because it opens a connection to the ssh port, reads the public
+key, and drops the connection as soon as it gets the key.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr sshd 8
+.Sh AUTHORS
+David Mazieres <dm@lcs.mit.edu>
+wrote the initial version, and
+Wayne Davison <wayned@users.sourceforge.net>
+added support for protocol version 2.
diff --git a/openssh/ssh-keyscan.c b/openssh/ssh-keyscan.c
new file mode 100644 (file)
index 0000000..3fbe88d
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
+ *
+ * Modification and redistribution in source and binary forms is
+ * permitted provided that due credit is given to the author and the
+ * OpenBSD project by leaving this copyright notice intact.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-keyscan.c,v 1.30 2001/10/08 19:05:05 markus Exp $");
+
+#if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H)
+#include <sys/queue.h>
+#else
+#include "openbsd-compat/fake-queue.h"
+#endif
+#include <errno.h>
+
+#include <openssl/bn.h>
+
+#include <setjmp.h>
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "key.h"
+#include "kex.h"
+#include "compat.h"
+#include "myproposal.h"
+#include "packet.h"
+#include "dispatch.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "log.h"
+#include "atomicio.h"
+#include "misc.h"
+
+/* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
+   Default value is AF_UNSPEC means both IPv4 and IPv6. */
+#ifdef IPV4_DEFAULT
+int IPv4or6 = AF_INET;
+#else
+int IPv4or6 = AF_UNSPEC;
+#endif
+
+int ssh_port = SSH_DEFAULT_PORT;
+
+#define KT_RSA1        1
+#define KT_DSA 2
+#define KT_RSA 4
+
+int get_keytypes = KT_RSA1;    /* Get only RSA1 keys by default */
+
+#define MAXMAXFD 256
+
+/* The number of seconds after which to give up on a TCP connection */
+int timeout = 5;
+
+int maxfd;
+#define MAXCON (maxfd - 10)
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+fd_set *read_wait;
+size_t read_wait_size;
+int ncon;
+int nonfatal_fatal = 0;
+jmp_buf kexjmp;
+Key *kexjmp_key;
+
+/*
+ * Keep a connection structure for each file descriptor.  The state
+ * associated with file descriptor n is held in fdcon[n].
+ */
+typedef struct Connection {
+       u_char c_status;        /* State of connection on this file desc. */
+#define CS_UNUSED 0            /* File descriptor unused */
+#define CS_CON 1               /* Waiting to connect/read greeting */
+#define CS_SIZE 2              /* Waiting to read initial packet size */
+#define CS_KEYS 3              /* Waiting to read public key packet */
+       int c_fd;               /* Quick lookup: c->c_fd == c - fdcon */
+       int c_plen;             /* Packet length field for ssh packet */
+       int c_len;              /* Total bytes which must be read. */
+       int c_off;              /* Length of data read so far. */
+       int c_keytype;          /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
+       char *c_namebase;       /* Address to free for c_name and c_namelist */
+       char *c_name;           /* Hostname of connection for errors */
+       char *c_namelist;       /* Pointer to other possible addresses */
+       char *c_output_name;    /* Hostname of connection for output */
+       char *c_data;           /* Data read from this fd */
+       Kex *c_kex;             /* The key-exchange struct for ssh2 */
+       struct timeval c_tv;    /* Time at which connection gets aborted */
+       TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
+} con;
+
+TAILQ_HEAD(conlist, Connection) tq;    /* Timeout Queue */
+con *fdcon;
+
+/*
+ *  This is just a wrapper around fgets() to make it usable.
+ */
+
+/* Stress-test.  Increase this later. */
+#define LINEBUF_SIZE 16
+
+typedef struct {
+       char *buf;
+       u_int size;
+       int lineno;
+       const char *filename;
+       FILE *stream;
+       void (*errfun) (const char *,...);
+} Linebuf;
+
+static Linebuf *
+Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
+{
+       Linebuf *lb;
+
+       if (!(lb = malloc(sizeof(*lb)))) {
+               if (errfun)
+                       (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
+               return (NULL);
+       }
+       if (filename) {
+               lb->filename = filename;
+               if (!(lb->stream = fopen(filename, "r"))) {
+                       xfree(lb);
+                       if (errfun)
+                               (*errfun) ("%s: %s\n", filename, strerror(errno));
+                       return (NULL);
+               }
+       } else {
+               lb->filename = "(stdin)";
+               lb->stream = stdin;
+       }
+
+       if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) {
+               if (errfun)
+                       (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
+               xfree(lb);
+               return (NULL);
+       }
+       lb->errfun = errfun;
+       lb->lineno = 0;
+       return (lb);
+}
+
+static void
+Linebuf_free(Linebuf * lb)
+{
+       fclose(lb->stream);
+       xfree(lb->buf);
+       xfree(lb);
+}
+
+#if 0
+static void
+Linebuf_restart(Linebuf * lb)
+{
+       clearerr(lb->stream);
+       rewind(lb->stream);
+       lb->lineno = 0;
+}
+
+static int
+Linebuf_lineno(Linebuf * lb)
+{
+       return (lb->lineno);
+}
+#endif
+
+static char *
+Linebuf_getline(Linebuf * lb)
+{
+       int n = 0;
+
+       lb->lineno++;
+       for (;;) {
+               /* Read a line */
+               if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
+                       if (ferror(lb->stream) && lb->errfun)
+                               (*lb->errfun) ("%s: %s\n", lb->filename,
+                                   strerror(errno));
+                       return (NULL);
+               }
+               n = strlen(lb->buf);
+
+               /* Return it or an error if it fits */
+               if (n > 0 && lb->buf[n - 1] == '\n') {
+                       lb->buf[n - 1] = '\0';
+                       return (lb->buf);
+               }
+               if (n != lb->size - 1) {
+                       if (lb->errfun)
+                               (*lb->errfun) ("%s: skipping incomplete last line\n",
+                                   lb->filename);
+                       return (NULL);
+               }
+               /* Double the buffer if we need more space */
+               if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) {
+                       if (lb->errfun)
+                               (*lb->errfun) ("linebuf (%s): realloc failed\n",
+                                   lb->filename);
+                       return (NULL);
+               }
+       }
+}
+
+static int
+fdlim_get(int hard)
+{
+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
+       struct rlimit rlfd;
+
+       if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
+               return (-1);
+       if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
+               return 10000;
+       else
+               return hard ? rlfd.rlim_max : rlfd.rlim_cur;
+#elif defined (HAVE_SYSCONF)
+       return sysconf (_SC_OPEN_MAX);
+#else
+       return 10000;
+#endif
+}
+
+static int
+fdlim_set(int lim)
+{
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
+       struct rlimit rlfd;
+#endif
+       if (lim <= 0)
+               return (-1);
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
+       if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
+               return (-1);
+       rlfd.rlim_cur = lim;
+       if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
+               return (-1);
+#elif defined (HAVE_SETDTABLESIZE)
+       setdtablesize(lim);
+#endif
+       return (0);
+}
+
+/*
+ * This is an strsep function that returns a null field for adjacent
+ * separators.  This is the same as the 4.4BSD strsep, but different from the
+ * one in the GNU libc.
+ */
+static char *
+xstrsep(char **str, const char *delim)
+{
+       char *s, *e;
+
+       if (!**str)
+               return (NULL);
+
+       s = *str;
+       e = s + strcspn(s, delim);
+
+       if (*e != '\0')
+               *e++ = '\0';
+       *str = e;
+
+       return (s);
+}
+
+/*
+ * Get the next non-null token (like GNU strsep).  Strsep() will return a
+ * null token for two adjacent separators, so we may have to loop.
+ */
+static char *
+strnnsep(char **stringp, char *delim)
+{
+       char *tok;
+
+       do {
+               tok = xstrsep(stringp, delim);
+       } while (tok && *tok == '\0');
+       return (tok);
+}
+
+static Key *
+keygrab_ssh1(con *c)
+{
+       static Key *rsa;
+       static Buffer msg;
+
+       if (rsa == NULL) {
+               buffer_init(&msg);
+               rsa = key_new(KEY_RSA1);
+       }
+       buffer_append(&msg, c->c_data, c->c_plen);
+       buffer_consume(&msg, 8 - (c->c_plen & 7));      /* padding */
+       if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
+               error("%s: invalid packet type", c->c_name);
+               buffer_clear(&msg);
+               return NULL;
+       }
+       buffer_consume(&msg, 8);                /* cookie */
+
+       /* server key */
+       (void) buffer_get_int(&msg);
+       buffer_get_bignum(&msg, rsa->rsa->e);
+       buffer_get_bignum(&msg, rsa->rsa->n);
+
+       /* host key */
+       (void) buffer_get_int(&msg);
+       buffer_get_bignum(&msg, rsa->rsa->e);
+       buffer_get_bignum(&msg, rsa->rsa->n);
+
+       buffer_clear(&msg);
+
+       return (rsa);
+}
+
+static int
+hostjump(Key *hostkey)
+{
+       kexjmp_key = hostkey;
+       longjmp(kexjmp, 1);
+}
+
+static int
+ssh2_capable(int remote_major, int remote_minor)
+{
+       switch (remote_major) {
+       case 1:
+               if (remote_minor == 99)
+                       return 1;
+               break;
+       case 2:
+               return 1;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static Key *
+keygrab_ssh2(con *c)
+{
+       int j;
+
+       packet_set_connection(c->c_fd, c->c_fd);
+       enable_compat20();
+       myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
+           "ssh-dss": "ssh-rsa";
+       c->c_kex = kex_setup(myproposal);
+       c->c_kex->verify_host_key = hostjump;
+
+       if (!(j = setjmp(kexjmp))) {
+               nonfatal_fatal = 1;
+               dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
+               fprintf(stderr, "Impossible! dispatch_run() returned!\n");
+               exit(1);
+       }
+       nonfatal_fatal = 0;
+       xfree(c->c_kex);
+       c->c_kex = NULL;
+       packet_close();
+
+       return j < 0? NULL : kexjmp_key;
+}
+
+static void
+keyprint(con *c, Key *key)
+{
+       if (!key)
+               return;
+
+       fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name);
+       key_write(key, stdout);
+       fputs("\n", stdout);
+}
+
+static int
+tcpconnect(char *host)
+{
+       struct addrinfo hints, *ai, *aitop;
+       char strport[NI_MAXSERV];
+       int gaierr, s = -1;
+
+       snprintf(strport, sizeof strport, "%d", ssh_port);
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_socktype = SOCK_STREAM;
+       if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
+               fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               s = socket(ai->ai_family, SOCK_STREAM, 0);
+               if (s < 0) {
+                       error("socket: %s", strerror(errno));
+                       continue;
+               }
+               if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
+                       fatal("F_SETFL: %s", strerror(errno));
+               if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
+                   errno != EINPROGRESS)
+                       error("connect (`%s'): %s", host, strerror(errno));
+               else
+                       break;
+               close(s);
+               s = -1;
+       }
+       freeaddrinfo(aitop);
+       return s;
+}
+
+static int
+conalloc(char *iname, char *oname, int keytype)
+{
+       int s;
+       char *namebase, *name, *namelist;
+
+       namebase = namelist = xstrdup(iname);
+
+       do {
+               name = xstrsep(&namelist, ",");
+               if (!name) {
+                       xfree(namebase);
+                       return (-1);
+               }
+       } while ((s = tcpconnect(name)) < 0);
+
+       if (s >= maxfd)
+               fatal("conalloc: fdno %d too high", s);
+       if (fdcon[s].c_status)
+               fatal("conalloc: attempt to reuse fdno %d", s);
+
+       fdcon[s].c_fd = s;
+       fdcon[s].c_status = CS_CON;
+       fdcon[s].c_namebase = namebase;
+       fdcon[s].c_name = name;
+       fdcon[s].c_namelist = namelist;
+       fdcon[s].c_output_name = xstrdup(oname);
+       fdcon[s].c_data = (char *) &fdcon[s].c_plen;
+       fdcon[s].c_len = 4;
+       fdcon[s].c_off = 0;
+       fdcon[s].c_keytype = keytype;
+       gettimeofday(&fdcon[s].c_tv, NULL);
+       fdcon[s].c_tv.tv_sec += timeout;
+       TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
+       FD_SET(s, read_wait);
+       ncon++;
+       return (s);
+}
+
+static void
+confree(int s)
+{
+       if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
+               fatal("confree: attempt to free bad fdno %d", s);
+       close(s);
+       xfree(fdcon[s].c_namebase);
+       xfree(fdcon[s].c_output_name);
+       if (fdcon[s].c_status == CS_KEYS)
+               xfree(fdcon[s].c_data);
+       fdcon[s].c_status = CS_UNUSED;
+       fdcon[s].c_keytype = 0;
+       TAILQ_REMOVE(&tq, &fdcon[s], c_link);
+       FD_CLR(s, read_wait);
+       ncon--;
+}
+
+static void
+contouch(int s)
+{
+       TAILQ_REMOVE(&tq, &fdcon[s], c_link);
+       gettimeofday(&fdcon[s].c_tv, NULL);
+       fdcon[s].c_tv.tv_sec += timeout;
+       TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
+}
+
+static int
+conrecycle(int s)
+{
+       int ret;
+       con *c = &fdcon[s];
+
+       ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
+       confree(s);
+       return (ret);
+}
+
+static void
+congreet(int s)
+{
+       char buf[256], *cp;
+       size_t bufsiz;
+       int n = 0;
+       con *c = &fdcon[s];
+
+       bufsiz = sizeof(buf);
+       cp = buf;
+       while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n') {
+               if (*cp == '\r')
+                       *cp = '\n';
+               cp++;
+       }
+       if (n < 0) {
+               if (errno != ECONNREFUSED)
+                       error("read (%s): %s", c->c_name, strerror(errno));
+               conrecycle(s);
+               return;
+       }
+       if (*cp != '\n' && *cp != '\r') {
+               error("%s: bad greeting", c->c_name);
+               confree(s);
+               return;
+       }
+       *cp = '\0';
+       if (c->c_keytype != KT_RSA1) {
+               int remote_major, remote_minor;
+               char remote_version[sizeof buf];
+
+               if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
+                   &remote_major, &remote_minor, remote_version) == 3)
+                       compat_datafellows(remote_version);
+               else
+                       datafellows = 0;
+               if (!ssh2_capable(remote_major, remote_minor)) {
+                       debug("%s doesn't support ssh2", c->c_name);
+                       confree(s);
+                       return;
+               }
+       }
+       fprintf(stderr, "# %s %s\n", c->c_name, chop(buf));
+       n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
+           c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
+           c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
+       if (atomicio(write, s, buf, n) != n) {
+               error("write (%s): %s", c->c_name, strerror(errno));
+               confree(s);
+               return;
+       }
+       if (c->c_keytype != KT_RSA1) {
+               keyprint(c, keygrab_ssh2(c));
+               confree(s);
+               return;
+       }
+       c->c_status = CS_SIZE;
+       contouch(s);
+}
+
+static void
+conread(int s)
+{
+       int n;
+       con *c = &fdcon[s];
+
+       if (c->c_status == CS_CON) {
+               congreet(s);
+               return;
+       }
+       n = read(s, c->c_data + c->c_off, c->c_len - c->c_off);
+       if (n < 0) {
+               error("read (%s): %s", c->c_name, strerror(errno));
+               confree(s);
+               return;
+       }
+       c->c_off += n;
+
+       if (c->c_off == c->c_len)
+               switch (c->c_status) {
+               case CS_SIZE:
+                       c->c_plen = htonl(c->c_plen);
+                       c->c_len = c->c_plen + 8 - (c->c_plen & 7);
+                       c->c_off = 0;
+                       c->c_data = xmalloc(c->c_len);
+                       c->c_status = CS_KEYS;
+                       break;
+               case CS_KEYS:
+                       keyprint(c, keygrab_ssh1(c));
+                       confree(s);
+                       return;
+                       break;
+               default:
+                       fatal("conread: invalid status %d", c->c_status);
+                       break;
+               }
+
+       contouch(s);
+}
+
+static void
+conloop(void)
+{
+       fd_set *r, *e;
+       struct timeval seltime, now;
+       int i;
+       con *c;
+
+       gettimeofday(&now, NULL);
+       c = tq.tqh_first;
+
+       if (c && (c->c_tv.tv_sec > now.tv_sec ||
+           (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
+               seltime = c->c_tv;
+               seltime.tv_sec -= now.tv_sec;
+               seltime.tv_usec -= now.tv_usec;
+               if (seltime.tv_usec < 0) {
+                       seltime.tv_usec += 1000000;
+                       seltime.tv_sec--;
+               }
+       } else
+               seltime.tv_sec = seltime.tv_usec = 0;
+
+       r = xmalloc(read_wait_size);
+       memcpy(r, read_wait, read_wait_size);
+       e = xmalloc(read_wait_size);
+       memcpy(e, read_wait, read_wait_size);
+
+       while (select(maxfd, r, NULL, e, &seltime) == -1 &&
+           (errno == EAGAIN || errno == EINTR))
+               ;
+
+       for (i = 0; i < maxfd; i++) {
+               if (FD_ISSET(i, e)) {
+                       error("%s: exception!", fdcon[i].c_name);
+                       confree(i);
+               } else if (FD_ISSET(i, r))
+                       conread(i);
+       }
+       xfree(r);
+       xfree(e);
+
+       c = tq.tqh_first;
+       while (c && (c->c_tv.tv_sec < now.tv_sec ||
+           (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
+               int s = c->c_fd;
+
+               c = c->c_link.tqe_next;
+               conrecycle(s);
+       }
+}
+
+static void
+do_host(char *host)
+{
+       char *name = strnnsep(&host, " \t\n");
+       int j;
+
+       for (j = KT_RSA1; j <= KT_RSA; j *= 2) {
+               if (get_keytypes & j) {
+                       while (ncon >= MAXCON)
+                               conloop();
+                       conalloc(name, *host ? host : name, j);
+               }
+       }
+}
+
+static void
+fatal_callback(void *arg)
+{
+       if (nonfatal_fatal)
+               longjmp(kexjmp, -1);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: %s [options] host ...\n",
+           __progname);
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "  -f file     Read hosts or addresses from file.\n");
+       fprintf(stderr, "  -p port     Connect to the specified port.\n");
+       fprintf(stderr, "  -t keytype  Specify the host key type.\n");
+       fprintf(stderr, "  -T timeout  Set connection timeout.\n");
+        fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
+        fprintf(stderr, "  -4          Use IPv4 only.\n");
+        fprintf(stderr, "  -6          Use IPv6 only.\n");
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
+       int opt, fopt_count = 0;
+       char *tname;
+
+       extern int optind;
+       extern char *optarg;
+
+       __progname = get_progname(argv[0]);
+       init_rng();
+       seed_rng();
+       TAILQ_INIT(&tq);
+
+       if (argc <= 1)
+               usage();
+
+       while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
+               switch (opt) {
+               case 'p':
+                       ssh_port = a2port(optarg);
+                       if (ssh_port == 0) {
+                               fprintf(stderr, "Bad port '%s'\n", optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'T':
+                       timeout = atoi(optarg);
+                       if (timeout <= 0)
+                               usage();
+                       break;
+               case 'v':
+                       if (!debug_flag) {
+                               debug_flag = 1;
+                               log_level = SYSLOG_LEVEL_DEBUG1;
+                       }
+                       else if (log_level < SYSLOG_LEVEL_DEBUG3)
+                               log_level++;
+                       else
+                               fatal("Too high debugging level.");
+                       break;
+               case 'f':
+                       if (strcmp(optarg, "-") == 0)
+                               optarg = NULL;
+                       argv[fopt_count++] = optarg;
+                       break;
+               case 't':
+                       get_keytypes = 0;
+                       tname = strtok(optarg, ",");
+                       while (tname) {
+                               int type = key_type_from_name(tname);
+                               switch (type) {
+                               case KEY_RSA1:
+                                       get_keytypes |= KT_RSA1;
+                                       break;
+                               case KEY_DSA:
+                                       get_keytypes |= KT_DSA;
+                                       break;
+                               case KEY_RSA:
+                                       get_keytypes |= KT_RSA;
+                                       break;
+                               case KEY_UNSPEC:
+                                       fatal("unknown key type %s\n", tname);
+                               }
+                               tname = strtok(NULL, ",");
+                       }
+                       break;
+               case '4':
+                       IPv4or6 = AF_INET;
+                       break;
+               case '6':
+                       IPv4or6 = AF_INET6;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       }
+       if (optind == argc && !fopt_count)
+               usage();
+
+       log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
+       fatal_add_cleanup(fatal_callback, NULL);
+
+       maxfd = fdlim_get(1);
+       if (maxfd < 0)
+               fatal("%s: fdlim_get: bad value", __progname);
+       if (maxfd > MAXMAXFD)
+               maxfd = MAXMAXFD;
+       if (MAXCON <= 0)
+               fatal("%s: not enough file descriptors", __progname);
+       if (maxfd > fdlim_get(0))
+               fdlim_set(maxfd);
+       fdcon = xmalloc(maxfd * sizeof(con));
+       memset(fdcon, 0, maxfd * sizeof(con));
+
+       read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+       read_wait = xmalloc(read_wait_size);
+       memset(read_wait, 0, read_wait_size);
+
+       if (fopt_count) {
+               Linebuf *lb;
+               char *line;
+               int j;
+
+               for (j = 0; j < fopt_count; j++) {
+                       lb = Linebuf_alloc(argv[j], error);
+                       if (!lb)
+                               continue;
+                       while ((line = Linebuf_getline(lb)) != NULL)
+                               do_host(line);
+                       Linebuf_free(lb);
+               }
+       }
+
+       while (optind < argc)
+               do_host(argv[optind++]);
+
+       while (ncon > 0)
+               conloop();
+
+       return (0);
+}
diff --git a/openssh/ssh-rsa.c b/openssh/ssh-rsa.c
new file mode 100644 (file)
index 0000000..a6a703b
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh-rsa.c,v 1.13 2001/11/10 13:22:42 markus Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+#include "xmalloc.h"
+#include "log.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "key.h"
+#include "ssh-rsa.h"
+#include "compat.h"
+
+/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
+int
+ssh_rsa_sign(
+    Key *key,
+    u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       const EVP_MD *evp_md;
+       EVP_MD_CTX md;
+       u_char *digest, *sig, *ret;
+       u_int slen, dlen, len;
+       int ok, nid;
+       Buffer b;
+
+       if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
+               error("ssh_rsa_sign: no RSA key");
+               return -1;
+       }
+       if (datafellows & SSH_BUG_SIGBLOB) {
+               error("ssh_rsa_sign: SSH_BUG_SIGBLOB not supported");
+               return -1;
+       }
+       nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+       if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
+               error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
+               return -1;
+       }
+       dlen = evp_md->md_size;
+       digest = xmalloc(dlen);
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, NULL);
+
+       slen = RSA_size(key->rsa);
+       sig = xmalloc(slen);
+
+       ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
+       memset(digest, 'd', dlen);
+       xfree(digest);
+
+       if (ok != 1) {
+               int ecode = ERR_get_error();
+               error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL));
+               xfree(sig);
+               return -1;
+       }
+       if (len < slen) {
+               int diff = slen - len;
+               debug("slen %d > len %d", slen, len);
+               memmove(sig + diff, sig, len);
+               memset(sig, 0, diff);
+       } else if (len > slen) {
+               error("ssh_rsa_sign: slen %d slen2 %d", slen, len);
+               xfree(sig);
+               return -1;
+       }
+       /* encode signature */
+       buffer_init(&b);
+       buffer_put_cstring(&b, "ssh-rsa");
+       buffer_put_string(&b, sig, slen);
+       len = buffer_len(&b);
+       ret = xmalloc(len);
+       memcpy(ret, buffer_ptr(&b), len);
+       buffer_free(&b);
+       memset(sig, 's', slen);
+       xfree(sig);
+
+       if (lenp != NULL)
+               *lenp = len;
+       if (sigp != NULL)
+               *sigp = ret;
+       return 0;
+}
+
+int
+ssh_rsa_verify(
+    Key *key,
+    u_char *signature, int signaturelen,
+    u_char *data, int datalen)
+{
+       Buffer b;
+       const EVP_MD *evp_md;
+       EVP_MD_CTX md;
+       char *ktype;
+       u_char *sigblob, *digest;
+       u_int len, dlen;
+       int rlen, ret, nid;
+
+       if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
+               error("ssh_rsa_verify: no RSA key");
+               return -1;
+       }
+       if (datafellows & SSH_BUG_SIGBLOB) {
+               error("ssh_rsa_verify: SSH_BUG_SIGBLOB not supported");
+               return -1;
+       }
+       if (BN_num_bits(key->rsa->n) < 768) {
+               error("ssh_rsa_verify: n too small: %d bits",
+                   BN_num_bits(key->rsa->n));
+               return -1;
+       }
+       buffer_init(&b);
+       buffer_append(&b, signature, signaturelen);
+       ktype = buffer_get_string(&b, NULL);
+       if (strcmp("ssh-rsa", ktype) != 0) {
+               error("ssh_rsa_verify: cannot handle type %s", ktype);
+               buffer_free(&b);
+               xfree(ktype);
+               return -1;
+       }
+       xfree(ktype);
+       sigblob = buffer_get_string(&b, &len);
+       rlen = buffer_len(&b);
+       buffer_free(&b);
+       if(rlen != 0) {
+               error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
+               xfree(sigblob);
+               return -1;
+       }
+       nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+       if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
+               error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
+               xfree(sigblob);
+               return -1;
+       }
+       dlen = evp_md->md_size;
+       digest = xmalloc(dlen);
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, NULL);
+
+       ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
+       memset(digest, 'd', dlen);
+       xfree(digest);
+       memset(sigblob, 's', len);
+       xfree(sigblob);
+       if (ret == 0) {
+               int ecode = ERR_get_error();
+               error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL));
+       }
+       debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
+       return ret;
+}
diff --git a/openssh/ssh-rsa.h b/openssh/ssh-rsa.h
new file mode 100644 (file)
index 0000000..11d355d
--- /dev/null
@@ -0,0 +1,32 @@
+/*     $OpenBSD: ssh-rsa.h,v 1.5 2001/06/26 17:27:25 markus Exp $      */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SSH_RSA_H
+#define SSH_RSA_H
+
+int     ssh_rsa_sign(Key *, u_char **, int *, u_char *, int);
+int     ssh_rsa_verify(Key *, u_char *, int, u_char *, int);
+
+#endif
diff --git a/openssh/ssh.1 b/openssh/ssh.1
new file mode 100644 (file)
index 0000000..ad3c960
--- /dev/null
@@ -0,0 +1,1513 @@
+.\"  -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\"                    All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose.  Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell.  All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: ssh.1,v 1.141 2001/11/08 17:49:53 markus Exp $
+.Dd September 25, 1999
+.Dt SSH 1
+.Os
+.Sh NAME
+.Nm ssh
+.Nd OpenSSH SSH client (remote login program)
+.Sh SYNOPSIS
+.Nm ssh
+.Op Fl l Ar login_name
+.Ar hostname | user@hostname
+.Op Ar command
+.Pp
+.Nm ssh
+.Op Fl afgknqstvxACNPTX1246
+.Op Fl b Ar bind_address
+.Op Fl c Ar cipher_spec
+.Op Fl e Ar escape_char
+.Op Fl i Ar identity_file
+.Op Fl l Ar login_name
+.Op Fl m Ar mac_spec
+.Op Fl o Ar option
+.Op Fl p Ar port
+.Op Fl F Ar configfile
+.Oo Fl L Xo
+.Sm off
+.Ar port :
+.Ar host :
+.Ar hostport
+.Sm on
+.Xc
+.Oc
+.Oo Fl R Xo
+.Sm off
+.Ar port :
+.Ar host :
+.Ar hostport
+.Sm on
+.Xc
+.Oc
+.Op Fl D Ar port
+.Ar hostname | user@hostname
+.Op Ar command
+.Sh DESCRIPTION
+.Nm
+(SSH client) is a program for logging into a remote machine and for
+executing commands on a remote machine.
+It is intended to replace
+rlogin and rsh, and provide 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.
+.Pp
+.Nm
+connects and logs into the specified
+.Ar hostname .
+The user must prove
+his/her identity to the remote machine using one of several methods
+depending on the protocol version used:
+.Pp
+.Ss SSH protocol version 1
+.Pp
+First, if the machine the user logs in from is listed in
+.Pa /etc/hosts.equiv
+or
+.Pa /etc/shosts.equiv
+on the remote machine, and the user names are
+the same on both sides, the user is immediately permitted to log in.
+Second, if
+.Pa \&.rhosts
+or
+.Pa \&.shosts
+exists in the user's home directory on the
+remote machine and contains a line containing the name of the client
+machine and the name of the user on that machine, the user is
+permitted to log in.
+This form of authentication alone is normally not
+allowed by the server because it is not secure.
+.Pp
+The second authentication method is the
+.Pa rhosts
+or
+.Pa hosts.equiv
+method combined with RSA-based host authentication.
+It means that if the login would be permitted by
+.Pa $HOME/.rhosts ,
+.Pa $HOME/.shosts ,
+.Pa /etc/hosts.equiv ,
+or
+.Pa /etc/shosts.equiv ,
+and if additionally the server can verify the client's
+host key (see
+.Pa /etc/ssh_known_hosts
+and
+.Pa $HOME/.ssh/known_hosts
+in the
+.Sx FILES
+section), only then login is permitted.
+This authentication method closes security holes due to IP
+spoofing, DNS spoofing and routing spoofing.
+[Note to the administrator:
+.Pa /etc/hosts.equiv ,
+.Pa $HOME/.rhosts ,
+and the rlogin/rsh protocol in general, are inherently insecure and should be
+disabled if security is desired.]
+.Pp
+As a third authentication method,
+.Nm
+supports RSA based authentication.
+The scheme is based on public-key cryptography: there are cryptosystems
+where encryption and decryption are done using separate keys, and it
+is not possible to derive the decryption key from the encryption key.
+RSA is one such system.
+The idea is that each user creates a public/private
+key pair for authentication purposes.
+The server knows the public key, and only the user knows the private key.
+The file
+.Pa $HOME/.ssh/authorized_keys
+lists the public keys that are permitted for logging
+in.
+When the user logs in, the
+.Nm
+program tells the server which key pair it would like to use for
+authentication.
+The server checks if this key is permitted, and if
+so, sends the user (actually the
+.Nm
+program running on behalf of the user) a challenge, a random number,
+encrypted by the user's public key.
+The challenge can only be
+decrypted using the proper private key.
+The user's client then decrypts the
+challenge using the private key, proving that he/she knows the private
+key but without disclosing it to the server.
+.Pp
+.Nm
+implements the RSA authentication protocol automatically.
+The user creates his/her RSA key pair by running
+.Xr ssh-keygen 1 .
+This stores the private key in
+.Pa $HOME/.ssh/identity
+and the public key in
+.Pa $HOME/.ssh/identity.pub
+in the user's home directory.
+The user should then copy the
+.Pa identity.pub
+to
+.Pa $HOME/.ssh/authorized_keys
+in his/her home directory on the remote machine (the
+.Pa authorized_keys
+file corresponds to the conventional
+.Pa $HOME/.rhosts
+file, and has one key
+per line, though the lines can be very long).
+After this, the user can log in without giving the password.
+RSA authentication is much
+more secure than rhosts authentication.
+.Pp
+The most convenient way to use RSA authentication may be with an
+authentication agent.
+See
+.Xr ssh-agent 1
+for more information.
+.Pp
+If other authentication methods fail,
+.Nm
+prompts the user for a password.
+The password is sent to the remote
+host for checking; however, since all communications are encrypted,
+the password cannot be seen by someone listening on the network.
+.Pp
+.Ss SSH protocol version 2
+.Pp
+When a user connects using the protocol version 2
+different authentication methods are available.
+Using the default values for
+.Cm PreferredAuthentications ,
+the client will try to authenticate first using the hostbased method;
+if this method fails public key authentication is attempted,
+and finally if this method fails keyboard-interactive and
+password authentication are tried.
+.Pp
+The public key method is similar to RSA authentication described
+in the previous section and allows the RSA or DSA algorithm to be used:
+The client uses his private key,
+.Pa $HOME/.ssh/id_dsa
+or
+.Pa $HOME/.ssh/id_rsa ,
+to sign the session identifier and sends the result to the server.
+The server checks whether the matching public key is listed in
+.Pa $HOME/.ssh/authorized_keys
+and grants access if both the key is found and the signature is correct.
+The session identifier is derived from a shared Diffie-Hellman value
+and is only known to the client and the server.
+.Pp
+If public key authentication fails or is not available a password
+can be sent encrypted to the remote host for proving the user's identity.
+.Pp
+Additionally,
+.Nm
+supports hostbased or challenge response authentication.
+.Pp
+Protocol 2 provides additional mechanisms for confidentiality
+(the traffic is encrypted using 3DES, Blowfish, CAST128 or Arcfour)
+and integrity (hmac-md5, hmac-sha1).
+Note that protocol 1 lacks a strong mechanism for ensuring the
+integrity of the connection.
+.Pp
+.Ss Login session and remote execution
+.Pp
+When the user's identity has been accepted by the server, the server
+either executes the given command, or logs into the machine and gives
+the user a normal shell on the remote machine.
+All communication with
+the remote command or shell will be automatically encrypted.
+.Pp
+If a pseudo-terminal has been allocated (normal login session), the
+user may use the escape characters noted below.
+.Pp
+If no pseudo tty has been allocated, the
+session is transparent and can be used to reliably transfer binary
+data.
+On most systems, setting the escape character to
+.Dq none
+will also make the session transparent even if a tty is used.
+.Pp
+The session terminates when the command or shell on the remote
+machine exits and all X11 and TCP/IP connections have been closed.
+The exit status of the remote program is returned as the exit status
+of
+.Nm ssh .
+.Pp
+.Ss Escape Characters
+.Pp
+When a pseudo terminal has been requested, ssh supports a number of functions
+through the use of an escape character.
+.Pp
+A single tilde character can be sent as
+.Ic ~~
+or by following the tilde by a character other than those described below.
+The escape character must always follow a newline to be interpreted as
+special.
+The escape character can be changed in configuration files using the
+.Cm EscapeChar
+configuration directive or on the command line by the
+.Fl e
+option.
+.Pp
+The supported escapes (assuming the default
+.Ql ~ )
+are:
+.Bl -tag -width Ds
+.It Cm ~.
+Disconnect
+.It Cm ~^Z
+Background ssh
+.It Cm ~#
+List forwarded connections
+.It Cm ~&
+Background ssh at logout when waiting for forwarded connection / X11 sessions
+to terminate
+.It Cm ~?
+Display a list of escape characters
+.It Cm ~R
+Request rekeying of the connection (only useful for SSH protocol version 2
+and if the peer supports it)
+.El
+.Pp
+.Ss X11 and TCP forwarding
+.Pp
+If the
+.Cm ForwardX11
+variable is set to
+.Dq yes
+(or, see the description of the
+.Fl X
+and
+.Fl x
+options described later)
+and the user is using X11 (the
+.Ev DISPLAY
+environment variable is set), the connection to the X11 display is
+automatically forwarded to the remote side in such a way that any X11
+programs started from the shell (or command) will go through the
+encrypted channel, and the connection to the real X server will be made
+from the local machine.
+The user should not manually set
+.Ev DISPLAY .
+Forwarding of X11 connections can be
+configured on the command line or in configuration files.
+.Pp
+The
+.Ev DISPLAY
+value set by
+.Nm
+will point to the server machine, but with a display number greater
+than zero.
+This is normal, and happens because
+.Nm
+creates a
+.Dq proxy
+X server on the server machine for forwarding the
+connections over the encrypted channel.
+.Pp
+.Nm
+will also automatically set up Xauthority data on the server machine.
+For this purpose, it will generate a random authorization cookie,
+store it in Xauthority on the server, and verify that any forwarded
+connections carry this cookie and replace it by the real cookie when
+the connection is opened.
+The real authentication cookie is never
+sent to the server machine (and no cookies are sent in the plain).
+.Pp
+If the user is using an authentication agent, the connection to the agent
+is automatically forwarded to the remote side unless disabled on
+the command line or in a configuration file.
+.Pp
+Forwarding of arbitrary TCP/IP connections over the secure channel can
+be specified either on the command line or in a configuration file.
+One possible application of TCP/IP forwarding is a secure connection to an
+electronic purse; another is going through firewalls.
+.Pp
+.Ss Server authentication
+.Pp
+.Nm
+automatically maintains and checks a database containing
+identifications for all hosts it has ever been used with.
+Host keys are stored in
+.Pa $HOME/.ssh/known_hosts
+in the user's home directory.
+Additionally, the file
+.Pa /etc/ssh_known_hosts
+is automatically checked for known hosts.
+Any new hosts are automatically added to the user's file.
+If a host's identification
+ever changes,
+.Nm
+warns about this and disables password authentication to prevent a
+trojan horse from getting the user's password.
+Another purpose of
+this mechanism is to prevent man-in-the-middle attacks which could
+otherwise be used to circumvent the encryption.
+The
+.Cm StrictHostKeyChecking
+option (see below) can be used to prevent logins to machines whose
+host key is not known or has changed.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Disables forwarding of the authentication agent connection.
+.It Fl A
+Enables forwarding of the authentication agent connection.
+This can also be specified on a per-host basis in a configuration file.
+.It Fl b Ar bind_address
+Specify the interface to transmit from on machines with multiple
+interfaces or aliased addresses.
+.It Fl c Ar blowfish|3des|des
+Selects the cipher to use for encrypting the session.
+.Ar 3des
+is used by default.
+It is believed to be secure.
+.Ar 3des
+(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
+.Ar blowfish
+is a fast block cipher, it appears very secure and is much faster than
+.Ar 3des .
+.Ar des
+is only supported in the
+.Nm
+client for interoperability with legacy protocol 1 implementations
+that do not support the
+.Ar 3des
+cipher.  Its use is strongly discouraged due to cryptographic
+weaknesses.
+.It Fl c Ar cipher_spec
+Additionally, for protocol version 2 a comma-separated list of ciphers can
+be specified in order of preference.
+See
+.Cm Ciphers
+for more information.
+.It Fl e Ar ch|^ch|none
+Sets the escape character for sessions with a pty (default:
+.Ql ~ ) .
+The escape character is only recognized at the beginning of a line.
+The escape character followed by a dot
+.Pq Ql \&.
+closes the connection, followed
+by control-Z suspends the connection, and followed by itself sends the
+escape character once.
+Setting the character to
+.Dq none
+disables any escapes and makes the session fully transparent.
+.It Fl f
+Requests
+.Nm
+to go to background just before command execution.
+This is useful if
+.Nm
+is going to ask for passwords or passphrases, but the user
+wants it in the background.
+This implies
+.Fl n .
+The recommended way to start X11 programs at a remote site is with
+something like
+.Ic ssh -f host xterm .
+.It Fl g
+Allows remote hosts to connect to local forwarded ports.
+.It Fl i Ar identity_file
+Selects the file from which the identity (private key) for
+RSA or DSA authentication is read.
+Default is
+.Pa $HOME/.ssh/identity
+in the user's home directory.
+Identity files may also be specified on
+a per-host basis in the configuration file.
+It is possible to have multiple
+.Fl i
+options (and multiple identities specified in
+configuration files).
+.It Fl I Ar smartcard_device
+Specifies which smartcard device to use. The argument is
+the device
+.Nm
+should use to communicate with a smartcard used for storing the user's
+private RSA key.
+.It Fl k
+Disables forwarding of Kerberos tickets and AFS tokens.
+This may also be specified on a per-host basis in the configuration file.
+.It Fl l Ar login_name
+Specifies the user to log in as on the remote machine.
+This also may be specified on a per-host basis in the configuration file.
+.It Fl m Ar mac_spec
+Additionally, for protocol version 2 a comma-separated list of MAC
+(message authentication code) algorithms can
+be specified in order of preference.
+See the
+.Cm MACs
+keyword for more information.
+.It Fl n
+Redirects stdin from
+.Pa /dev/null
+(actually, prevents reading from stdin).
+This must be used when
+.Nm
+is run in the background.
+A common trick is to use this to run X11 programs on a remote machine.
+For example,
+.Ic ssh -n shadows.cs.hut.fi emacs &
+will start an emacs on shadows.cs.hut.fi, and the X11
+connection will be automatically forwarded over an encrypted channel.
+The
+.Nm
+program will be put in the background.
+(This does not work if
+.Nm
+needs to ask for a password or passphrase; see also the
+.Fl f
+option.)
+.It Fl N
+Do not execute a remote command.
+This is useful for just forwarding ports
+(protocol version 2 only).
+.It Fl o Ar option
+Can be used to give options in the format used in the configuration file.
+This is useful for specifying options for which there is no separate
+command-line flag.
+.It Fl p Ar port
+Port to connect to on the remote host.
+This can be specified on a
+per-host basis in the configuration file.
+.It Fl P
+Use a non-privileged port for outgoing connections.
+This can be used if a firewall does
+not permit connections from privileged ports.
+Note that this option turns off
+.Cm RhostsAuthentication
+and
+.Cm RhostsRSAAuthentication
+for older servers.
+.It Fl q
+Quiet mode.
+Causes all warning and diagnostic messages to be suppressed.
+Only fatal errors are displayed.
+.It Fl s
+May be used to request invocation of a subsystem on the remote system. Subsystems are a feature of the SSH2 protocol which facilitate the use
+of SSH as a secure transport for other applications (eg. sftp). The
+subsystem is specified as the remote command.
+.It Fl t
+Force pseudo-tty allocation.
+This can be used to execute arbitrary
+screen-based programs on a remote machine, which can be very useful,
+e.g., when implementing menu services.
+Multiple
+.Fl t
+options force tty allocation, even if
+.Nm
+has no local tty.
+.It Fl T
+Disable pseudo-tty allocation.
+.It Fl v
+Verbose mode.
+Causes
+.Nm
+to print debugging messages about its progress.
+This is helpful in
+debugging connection, authentication, and configuration problems.
+Multiple
+.Fl v
+options increases the verbosity.
+Maximum is 3.
+.It Fl x
+Disables X11 forwarding.
+.It Fl X
+Enables X11 forwarding.
+This can also be specified on a per-host basis in a configuration file.
+.It Fl C
+Requests compression of all data (including stdin, stdout, stderr, and
+data for forwarded X11 and TCP/IP connections).
+The compression algorithm is the same used by
+.Xr gzip 1 ,
+and the
+.Dq level
+can be controlled by the
+.Cm CompressionLevel
+option (see below).
+Compression is desirable on modem lines and other
+slow connections, but will only slow down things on fast networks.
+The default value can be set on a host-by-host basis in the
+configuration files; see the
+.Cm Compression
+option below.
+.It Fl F Ar configfile
+Specifies an alternative per-user configuration file.
+If a configuration file is given on the command line,
+the system-wide configuration file
+.Pq Pa /etc/ssh_config
+will be ignored.
+The default for the per-user configuration file is
+.Pa $HOME/.ssh/config .
+.It Fl L Ar port:host:hostport
+Specifies that the given port on the local (client) host is to be
+forwarded to the given host and port on the remote side.
+This works by allocating a socket to listen to
+.Ar port
+on the local side, and whenever a connection is made to this port, the
+connection is forwarded over the secure channel, and a connection is
+made to
+.Ar host
+port
+.Ar hostport
+from the remote machine.
+Port forwardings can also be specified in the configuration file.
+Only root can forward privileged ports.
+IPv6 addresses can be specified with an alternative syntax:
+.Ar port/host/hostport
+.It Fl R Ar port:host:hostport
+Specifies that the given port on the remote (server) host is to be
+forwarded to the given host and port on the local side.
+This works by allocating a socket to listen to
+.Ar port
+on the remote side, and whenever a connection is made to this port, the
+connection is forwarded over the secure channel, and a connection is
+made to
+.Ar host
+port
+.Ar hostport
+from the local machine.
+Port forwardings can also be specified in the configuration file.
+Privileged ports can be forwarded only when
+logging in as root on the remote machine.
+IPv6 addresses can be specified with an alternative syntax:
+.Ar port/host/hostport
+.It Fl D Ar port
+Specifies a local
+.Dq dynamic
+application-level port forwarding.
+This works by allocating a socket to listen to
+.Ar port
+on the local side, and whenever a connection is made to this port, the
+connection is forwarded over the secure channel, and the application
+protocol is then used to determine where to connect to from the
+remote machine.  Currently the SOCKS4 protocol is supported, and
+.Nm
+will act as a SOCKS4 server.
+Only root can forward privileged ports.
+Dynamic port forwardings can also be specified in the configuration file.
+.It Fl 1
+Forces
+.Nm
+to try protocol version 1 only.
+.It Fl 2
+Forces
+.Nm
+to try protocol version 2 only.
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.El
+.Sh CONFIGURATION FILES
+.Nm
+obtains configuration data from the following sources in
+the following order:
+command line options, user's configuration file
+.Pq Pa $HOME/.ssh/config ,
+and system-wide configuration file
+.Pq Pa /etc/ssh_config .
+For each parameter, the first obtained value
+will be used.
+The configuration files contain sections bracketed by
+.Dq Host
+specifications, and that section is only applied for hosts that
+match one of the patterns given in the specification.
+The matched host name is the one given on the command line.
+.Pp
+Since the first obtained value for each parameter is used, more
+host-specific declarations should be given near the beginning of the
+file, and general defaults at the end.
+.Pp
+The configuration file has the following format:
+.Pp
+Empty lines and lines starting with
+.Ql #
+are comments.
+.Pp
+Otherwise a line is of the format
+.Dq keyword arguments .
+Configuration options may be separated by whitespace or
+optional whitespace and exactly one
+.Ql = ;
+the latter format is useful to avoid the need to quote whitespace
+when specifying configuration options using the
+.Nm ssh ,
+.Nm scp
+and
+.Nm sftp
+.Fl o
+option.
+.Pp
+The possible
+keywords and their meanings are as follows (note that
+keywords are case-insensitive and arguments are case-sensitive):
+.Bl -tag -width Ds
+.It Cm Host
+Restricts the following declarations (up to the next
+.Cm Host
+keyword) to be only for those hosts that match one of the patterns
+given after the keyword.
+.Ql \&*
+and
+.Ql ?
+can be used as wildcards in the
+patterns.
+A single
+.Ql \&*
+as a pattern can be used to provide global
+defaults for all hosts.
+The host is the
+.Ar hostname
+argument given on the command line (i.e., the name is not converted to
+a canonicalized host name before matching).
+.It Cm AFSTokenPassing
+Specifies whether to pass AFS tokens to remote host.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+This option applies to protocol version 1 only.
+.It Cm BatchMode
+If set to
+.Dq yes ,
+passphrase/password querying will be disabled.
+This option is useful in scripts and other batch jobs where no user
+is present to supply the password.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm BindAddress
+Specify the interface to transmit from on machines with multiple
+interfaces or aliased addresses.
+Note that this option does not work if
+.Cm UsePrivilegedPort
+is set to
+.Dq yes .
+.It Cm CheckHostIP
+If this flag is set to
+.Dq yes ,
+ssh will additionally check the host IP address in the
+.Pa known_hosts
+file.
+This allows ssh to detect if a host key changed due to DNS spoofing.
+If the option is set to
+.Dq no ,
+the check will not be executed.
+The default is
+.Dq yes .
+.It Cm Cipher
+Specifies the cipher to use for encrypting the session
+in protocol version 1.
+Currently,
+.Dq blowfish ,
+.Dq 3des ,
+and
+.Dq des
+are supported.
+.Ar des
+is only supported in the
+.Nm
+client for interoperability with legacy protocol 1 implementations
+that do not support the
+.Ar 3des
+cipher.  Its use is strongly discouraged due to cryptographic
+weaknesses.
+The default is
+.Dq 3des .
+.It Cm Ciphers
+Specifies the ciphers allowed for protocol version 2
+in order of preference.
+Multiple ciphers must be comma-separated.
+The default is
+.Pp
+.Bd -literal
+  ``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
+    aes192-cbc,aes256-cbc''
+.Ed
+.It Cm ClearAllForwardings
+Specifies that all local, remote and dynamic port forwardings
+specified in the configuration files or on the command line be
+cleared.  This option is primarily useful when used from the
+.Nm
+command line to clear port forwardings set in
+configuration files, and is automatically set by
+.Xr scp 1
+and
+.Xr sftp 1 .
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm Compression
+Specifies whether to use compression.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm CompressionLevel
+Specifies the compression level to use if compression is enabled.
+The argument must be an integer from 1 (fast) to 9 (slow, best).
+The default level is 6, which is good for most applications.
+The meaning of the values is the same as in
+.Xr gzip 1 .
+Note that this option applies to protocol version 1 only.
+.It Cm ConnectionAttempts
+Specifies the number of tries (one per second) to make before falling
+back to rsh or exiting.
+The argument must be an integer.
+This may be useful in scripts if the connection sometimes fails.
+The default is 1.
+.It Cm DynamicForward
+Specifies that a TCP/IP port on the local machine be forwarded
+over the secure channel, and the application
+protocol is then used to determine where to connect to from the
+remote machine.  The argument must be a port number.
+Currently the SOCKS4 protocol is supported, and
+.Nm
+will act as a SOCKS4 server.
+Multiple forwardings may be specified, and
+additional forwardings can be given on the command line.  Only
+the superuser can forward privileged ports.
+.It Cm EscapeChar
+Sets the escape character (default:
+.Ql ~ ) .
+The escape character can also
+be set on the command line.
+The argument should be a single character,
+.Ql ^
+followed by a letter, or
+.Dq none
+to disable the escape
+character entirely (making the connection transparent for binary
+data).
+.It Cm FallBackToRsh
+Specifies that if connecting via
+.Nm
+fails due to a connection refused error (there is no
+.Xr sshd 8
+listening on the remote host),
+.Xr rsh 1
+should automatically be used instead (after a suitable warning about
+the session being unencrypted).
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm ForwardAgent
+Specifies whether the connection to the authentication agent (if any)
+will be forwarded to the remote machine.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm ForwardX11
+Specifies whether X11 connections will be automatically redirected
+over the secure channel and
+.Ev DISPLAY
+set.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm GatewayPorts
+Specifies whether remote hosts are allowed to connect to local
+forwarded ports.
+By default,
+.Nm
+binds local port forwardings to the loopback addresss.  This
+prevents other remote hosts from connecting to forwarded ports.
+.Cm GatewayPorts
+can be used to specify that
+.Nm
+should bind local port forwardings to the wildcard address,
+thus allowing remote hosts to connect to forwarded ports.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm GlobalKnownHostsFile
+Specifies a file to use for the global
+host key database instead of
+.Pa /etc/ssh_known_hosts .
+.It Cm HostbasedAuthentication
+Specifies whether to try rhosts based authentication with public key
+authentication.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+This option applies to protocol version 2 only and
+is similar to
+.Cm RhostsRSAAuthentication .
+.It Cm HostKeyAlgorithms
+Specifies the protocol version 2 host key algorithms
+that the client wants to use in order of preference.
+The default for this option is:
+.Dq ssh-rsa,ssh-dss
+.It Cm HostKeyAlias
+Specifies an alias that should be used instead of the
+real host name when looking up or saving the host key
+in the host key database files.
+This option is useful for tunneling ssh connections
+or for multiple servers running on a single host.
+.It Cm HostName
+Specifies the real host name to log into.
+This can be used to specify nicknames or abbreviations for hosts.
+Default is the name given on the command line.
+Numeric IP addresses are also permitted (both on the command line and in
+.Cm HostName
+specifications).
+.It Cm IdentityFile
+Specifies the file from which the user's RSA or DSA authentication identity
+is read (default
+.Pa $HOME/.ssh/identity
+in the user's home directory).
+Additionally, any identities represented by the authentication agent
+will be used for authentication.
+The file name may use the tilde
+syntax to refer to a user's home directory.
+It is possible to have
+multiple identity files specified in configuration files; all these
+identities will be tried in sequence.
+.It Cm KeepAlive
+Specifies whether the system should send keepalive messages to the
+other side.
+If they are sent, death of the connection or crash of one
+of the machines will be properly noticed.
+However, this means that
+connections will die if the route is down temporarily, and some people
+find it annoying.
+.Pp
+The default is
+.Dq yes
+(to send keepalives), and the client will notice
+if the network goes down or the remote host dies.
+This is important in scripts, and many users want it too.
+.Pp
+To disable keepalives, the value should be set to
+.Dq no
+in both the server and the client configuration files.
+.It Cm KerberosAuthentication
+Specifies whether Kerberos authentication will be used.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+.It Cm KerberosTgtPassing
+Specifies whether a Kerberos TGT will be forwarded to the server.
+This will only work if the Kerberos server is actually an AFS kaserver.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+.It Cm LocalForward
+Specifies that a TCP/IP port on the local machine be forwarded over
+the secure channel to the specified host and port from the remote machine.
+The first argument must be a port number, and the second must be
+.Ar host:port .
+IPv6 addresses can be specified with an alternative syntax:
+.Ar host/port .
+Multiple forwardings may be specified, and additional
+forwardings can be given on the command line.
+Only the superuser can forward privileged ports.
+.It Cm LogLevel
+Gives the verbosity level that is used when logging messages from
+.Nm ssh .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
+The default is INFO.
+.It Cm MACs
+Specifies the MAC (message authentication code) algorithms
+in order of preference.
+The MAC algorithm is used in protocol version 2
+for data integrity protection.
+Multiple algorithms must be comma-separated.
+The default is
+.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
+.It Cm NoHostAuthenticationForLocalhost
+This option can be used if the home directory is shared across machines.
+In this case localhost will refer to a different machine on each of
+the machines and the user will get many warnings about changed host keys.
+However, this option disables host authentication for localhost.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is to check the host key for localhost.
+.It Cm NumberOfPasswordPrompts
+Specifies the number of password prompts before giving up.
+The argument to this keyword must be an integer.
+Default is 3.
+.It Cm PasswordAuthentication
+Specifies whether to use password authentication.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+.It Cm Port
+Specifies the port number to connect on the remote host.
+Default is 22.
+.It Cm PreferredAuthentications
+Specifies the order in which the client should try protocol 2
+authentication methods. This allows a client to prefer one method (e.g.
+.Cm keyboard-interactive )
+over another method (e.g.
+.Cm password )
+The default for this option is:
+.Dq hostbased,publickey,keyboard-interactive,password
+.It Cm Protocol
+Specifies the protocol versions
+.Nm
+should support in order of preference.
+The possible values are
+.Dq 1
+and
+.Dq 2 .
+Multiple versions must be comma-separated.
+The default is
+.Dq 2,1 .
+This means that
+.Nm
+tries version 2 and falls back to version 1
+if version 2 is not available.
+.It Cm ProxyCommand
+Specifies the command to use to connect to the server.
+The command
+string extends to the end of the line, and is executed with
+.Pa /bin/sh .
+In the command string,
+.Ql %h
+will be substituted by the host name to
+connect and
+.Ql %p
+by the port.
+The command can be basically anything,
+and should read from its standard input and write to its standard output.
+It should eventually connect an
+.Xr sshd 8
+server running on some machine, or execute
+.Ic sshd -i
+somewhere.
+Host key management will be done using the
+HostName of the host being connected (defaulting to the name typed by
+the user).
+Note that
+.Cm CheckHostIP
+is not available for connects with a proxy command.
+.Pp
+.It Cm PubkeyAuthentication
+Specifies whether to try public key authentication.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+This option applies to protocol version 2 only.
+.It Cm RemoteForward
+Specifies that a TCP/IP port on the remote machine be forwarded over
+the secure channel to the specified host and port from the local machine.
+The first argument must be a port number, and the second must be
+.Ar host:port .
+IPv6 addresses can be specified with an alternative syntax:
+.Ar host/port .
+Multiple forwardings may be specified, and additional
+forwardings can be given on the command line.
+Only the superuser can forward privileged ports.
+.It Cm RhostsAuthentication
+Specifies whether to try rhosts based authentication.
+Note that this
+declaration only affects the client side and has no effect whatsoever
+on security.
+Disabling rhosts authentication may reduce
+authentication time on slow connections when rhosts authentication is
+not used.
+Most servers do not permit RhostsAuthentication because it
+is not secure (see
+.Cm RhostsRSAAuthentication ) .
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+This option applies to protocol version 1 only.
+.It Cm RhostsRSAAuthentication
+Specifies whether to try rhosts based authentication with RSA host
+authentication.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+This option applies to protocol version 1 only.
+.It Cm RSAAuthentication
+Specifies whether to try RSA authentication.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+RSA authentication will only be
+attempted if the identity file exists, or an authentication agent is
+running.
+The default is
+.Dq yes .
+Note that this option applies to protocol version 1 only.
+.It Cm ChallengeResponseAuthentication
+Specifies whether to use challenge response authentication.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+.It Cm SmartcardDevice
+Specifies which smartcard device to use. The argument to this keyword is
+the device
+.Nm
+should use to communicate with a smartcard used for storing the user's
+private RSA key. By default, no device is specified and smartcard support
+is not activated.
+.It Cm StrictHostKeyChecking
+If this flag is set to
+.Dq yes ,
+.Nm
+will never automatically add host keys to the
+.Pa $HOME/.ssh/known_hosts
+file, and refuses to connect to hosts whose host key has changed.
+This provides maximum protection against trojan horse attacks,
+however, can be annoying when the
+.Pa /etc/ssh_known_hosts
+file is poorly maintained, or connections to new hosts are
+frequently made.
+This option forces the user to manually
+add all new hosts.
+If this flag is set to
+.Dq no ,
+.Nm
+will automatically add new host keys to the
+user known hosts files.
+If this flag is set to
+.Dq ask ,
+new host keys
+will be added to the user known host files only after the user
+has confirmed that is what they really want to do, and
+.Nm
+will refuse to connect to hosts whose host key has changed.
+The host keys of
+known hosts will be verified automatically in all cases.
+The argument must be
+.Dq yes ,
+.Dq no
+or
+.Dq ask .
+The default is
+.Dq ask .
+.It Cm UsePrivilegedPort
+Specifies whether to use a privileged port for outgoing connections.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+Note that this option must be set to
+.Dq yes
+if
+.Cm RhostsAuthentication
+and
+.Cm RhostsRSAAuthentication
+authentications are needed with older servers.
+.It Cm User
+Specifies the user to log in as.
+This can be useful when a different user name is used on different machines.
+This saves the trouble of
+having to remember to give the user name on the command line.
+.It Cm UserKnownHostsFile
+Specifies a file to use for the user
+host key database instead of
+.Pa $HOME/.ssh/known_hosts .
+.It Cm UseRsh
+Specifies that rlogin/rsh should be used for this host.
+It is possible that the host does not at all support the
+.Nm
+protocol.
+This causes
+.Nm
+to immediately execute
+.Xr rsh 1 .
+All other options (except
+.Cm HostName )
+are ignored if this has been specified.
+The argument must be
+.Dq yes
+or
+.Dq no .
+.It Cm XAuthLocation
+Specifies the location of the
+.Xr xauth 1
+program.
+The default is
+.Pa /usr/X11R6/bin/xauth .
+.El
+.Sh ENVIRONMENT
+.Nm
+will normally set the following environment variables:
+.Bl -tag -width Ds
+.It Ev DISPLAY
+The
+.Ev DISPLAY
+variable indicates the location of the X11 server.
+It is automatically set by
+.Nm
+to point to a value of the form
+.Dq hostname:n
+where hostname indicates
+the host where the shell runs, and n is an integer >= 1.
+.Nm
+uses this special value to forward X11 connections over the secure
+channel.
+The user should normally not set
+.Ev DISPLAY
+explicitly, as that
+will render the X11 connection insecure (and will require the user to
+manually copy any required authorization cookies).
+.It Ev HOME
+Set to the path of the user's home directory.
+.It Ev LOGNAME
+Synonym for
+.Ev USER ;
+set for compatibility with systems that use this variable.
+.It Ev MAIL
+Set to the path of the user's mailbox.
+.It Ev PATH
+Set to the default
+.Ev PATH ,
+as specified when compiling
+.Nm ssh .
+.It Ev SSH_ASKPASS
+If
+.Nm
+needs a passphrase, it will read the passphrase from the current
+terminal if it was run from a terminal.
+If
+.Nm
+does not have a terminal associated with it but
+.Ev DISPLAY
+and
+.Ev SSH_ASKPASS
+are set, it will execute the program specified by
+.Ev SSH_ASKPASS
+and open an X11 window to read the passphrase.
+This is particularly useful when calling
+.Nm
+from a
+.Pa .Xsession
+or related script.
+(Note that on some machines it
+may be necessary to redirect the input from
+.Pa /dev/null
+to make this work.)
+.It Ev SSH_AUTH_SOCK
+Identifies the path of a unix-domain socket used to communicate with the
+agent.
+.It Ev SSH_CLIENT
+Identifies the client end of the connection.
+The variable contains
+three space-separated values: client ip-address, client port number,
+and server port number.
+.It Ev SSH_ORIGINAL_COMMAND
+The variable contains the original command line if a forced command
+is executed.
+It can be used to extract the original arguments.
+.It Ev SSH_TTY
+This is set to the name of the tty (path to the device) associated
+with the current shell or command.
+If the current session has no tty,
+this variable is not set.
+.It Ev TZ
+The timezone variable is set to indicate the present timezone if it
+was set when the daemon was started (i.e., the daemon passes the value
+on to new connections).
+.It Ev USER
+Set to the name of the user logging in.
+.El
+.Pp
+Additionally,
+.Nm
+reads
+.Pa $HOME/.ssh/environment ,
+and adds lines of the format
+.Dq VARNAME=value
+to the environment.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $HOME/.ssh/known_hosts
+Records host keys for all hosts the user has logged into that are not
+in
+.Pa /etc/ssh_known_hosts .
+See
+.Xr sshd 8 .
+.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa, $HOME/.ssh/id_rsa
+Contains the authentication identity of the user.
+They are for protocol 1 RSA, protocol 2 DSA, and protocol 2 RSA, respectively.
+These files
+contain sensitive data and should be readable by the user but not
+accessible by others (read/write/execute).
+Note that
+.Nm
+ignores a private key file if it is accessible by others.
+It is possible to specify a passphrase when
+generating the key; the passphrase will be used to encrypt the
+sensitive part of this file using 3DES.
+.It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub, $HOME/.ssh/id_rsa.pub
+Contains the public key for authentication (public part of the
+identity file in human-readable form).
+The contents of the
+.Pa $HOME/.ssh/identity.pub
+file should be added to
+.Pa $HOME/.ssh/authorized_keys
+on all machines
+where the user wishes to log in using protocol version 1 RSA authentication.
+The contents of the
+.Pa $HOME/.ssh/id_dsa.pub
+and
+.Pa $HOME/.ssh/id_rsa.pub
+file should be added to
+.Pa $HOME/.ssh/authorized_keys
+on all machines
+where the user wishes to log in using protocol version 2 DSA/RSA authentication.
+These files are not
+sensitive and can (but need not) be readable by anyone.
+These files are
+never used automatically and are not necessary; they are only provided for
+the convenience of the user.
+.It Pa $HOME/.ssh/config
+This is the per-user configuration file.
+The format of this file is described above.
+This file is used by the
+.Nm
+client.
+This file does not usually contain any sensitive information,
+but the recommended permissions are read/write for the user, and not
+accessible by others.
+.It Pa $HOME/.ssh/authorized_keys
+Lists the public keys (RSA/DSA) that can be used for logging in as this user.
+The format of this file is described in the
+.Xr sshd 8
+manual page.
+In the simplest form the format is the same as the .pub
+identity files.
+This file is not highly sensitive, but the recommended
+permissions are read/write for the user, and not accessible by others.
+.It Pa /etc/ssh_known_hosts
+Systemwide list of known host keys.
+This file should be prepared by the
+system administrator to contain the public host keys of all machines in the
+organization.
+This file should be world-readable.
+This file contains
+public keys, one per line, in the following format (fields separated
+by spaces): system name, public key and optional comment field.
+When different names are used
+for the same machine, all such names should be listed, separated by
+commas.
+The format is described on the
+.Xr sshd 8
+manual page.
+.Pp
+The canonical system name (as returned by name servers) is used by
+.Xr sshd 8
+to verify the client host when logging in; other names are needed because
+.Nm
+does not convert the user-supplied name to a canonical name before
+checking the key, because someone with access to the name servers
+would then be able to fool host authentication.
+.It Pa /etc/ssh_config
+Systemwide configuration file.
+This file provides defaults for those
+values that are not specified in the user's configuration file, and
+for those users who do not have a configuration file.
+This file must be world-readable.
+.It Pa /etc/ssh_host_key, /etc/ssh_host_dsa_key, /etc/ssh_host_rsa_key
+These three files contain the private parts of the host keys
+and are used for
+.Cm RhostsRSAAuthentication
+and
+.Cm HostbasedAuthentication .
+Since they are readable only by root
+.Nm
+must be setuid root if these authentication methods are desired.
+.It Pa $HOME/.rhosts
+This file is used in
+.Pa \&.rhosts
+authentication to list the
+host/user pairs that are permitted to log in.
+(Note that this file is
+also used by rlogin and rsh, which makes using this file insecure.)
+Each line of the file contains a host name (in the canonical form
+returned by name servers), and then a user name on that host,
+separated by a space.
+On some machines this file may need to be
+world-readable if the user's home directory is on a NFS partition,
+because
+.Xr sshd 8
+reads it as root.
+Additionally, this file must be owned by the user,
+and must not have write permissions for anyone else.
+The recommended
+permission for most machines is read/write for the user, and not
+accessible by others.
+.Pp
+Note that by default
+.Xr sshd 8
+will be installed so that it requires successful RSA host
+authentication before permitting \s+2.\s0rhosts authentication.
+If the server machine does not have the client's host key in
+.Pa /etc/ssh_known_hosts ,
+it can be stored in
+.Pa $HOME/.ssh/known_hosts .
+The easiest way to do this is to
+connect back to the client from the server machine using ssh; this
+will automatically add the host key to
+.Pa $HOME/.ssh/known_hosts .
+.It Pa $HOME/.shosts
+This file is used exactly the same way as
+.Pa \&.rhosts .
+The purpose for
+having this file is to be able to use rhosts authentication with
+.Nm
+without permitting login with
+.Xr rlogin 1
+or
+.Xr rsh 1 .
+.It Pa /etc/hosts.equiv
+This file is used during
+.Pa \&.rhosts authentication.
+It contains
+canonical hosts names, one per line (the full format is described on
+the
+.Xr sshd 8
+manual page).
+If the client host is found in this file, login is
+automatically permitted provided client and server user names are the
+same.
+Additionally, successful RSA host authentication is normally
+required.
+This file should only be writable by root.
+.It Pa /etc/shosts.equiv
+This file is processed exactly as
+.Pa /etc/hosts.equiv .
+This file may be useful to permit logins using
+.Nm
+but not using rsh/rlogin.
+.It Pa /etc/sshrc
+Commands in this file are executed by
+.Nm
+when the user logs in just before the user's shell (or command) is started.
+See the
+.Xr sshd 8
+manual page for more information.
+.It Pa $HOME/.ssh/rc
+Commands in this file are executed by
+.Nm
+when the user logs in just before the user's shell (or command) is
+started.
+See the
+.Xr sshd 8
+manual page for more information.
+.It Pa $HOME/.ssh/environment
+Contains additional definitions for environment variables, see section
+.Sx ENVIRONMENT
+above.
+.El
+.Sh AUTHORS
+OpenSSH is a derivative of the original and free
+ssh 1.2.12 release by Tatu Ylonen.
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
+Theo de Raadt and Dug Song
+removed many bugs, re-added newer features and
+created OpenSSH.
+Markus Friedl contributed the support for SSH
+protocol versions 1.5 and 2.0.
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr rsh 1 ,
+.Xr scp 1 ,
+.Xr sftp 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr telnet 1 ,
+.Xr sshd 8
+.Rs
+.%A T. Ylonen
+.%A T. Kivinen
+.%A M. Saarinen
+.%A T. Rinne
+.%A S. Lehtinen
+.%T "SSH Protocol Architecture"
+.%N draft-ietf-secsh-architecture-09.txt
+.%D July 2001
+.%O work in progress material
+.Re
diff --git a/openssh/ssh.c b/openssh/ssh.c
new file mode 100644 (file)
index 0000000..2984a59
--- /dev/null
@@ -0,0 +1,1225 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Ssh client program.  This program can be used to log into a remote machine.
+ * The software supports strong authentication, encryption, and forwarding
+ * of X11, TCP/IP, and authentication connections.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 1999 Niels Provos.  All rights reserved.
+ *
+ * Modified to work with SSL by Niels Provos <provos@citi.umich.edu>
+ * in Canada (German citizen).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ssh.c,v 1.149 2001/10/24 08:51:35 markus Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "compat.h"
+#include "cipher.h"
+#include "xmalloc.h"
+#include "packet.h"
+#include "buffer.h"
+#include "uidswap.h"
+#include "channels.h"
+#include "key.h"
+#include "authfd.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "clientloop.h"
+#include "log.h"
+#include "readconf.h"
+#include "sshconnect.h"
+#include "tildexpand.h"
+#include "dispatch.h"
+#include "misc.h"
+#include "kex.h"
+#include "mac.h"
+#include "sshtty.h"
+
+#ifdef SMARTCARD
+#include <openssl/engine.h>
+#include "scard.h"
+#endif
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+/* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
+   Default value is AF_UNSPEC means both IPv4 and IPv6. */
+#ifdef IPV4_DEFAULT
+int IPv4or6 = AF_INET;
+#else
+int IPv4or6 = AF_UNSPEC;
+#endif
+
+/* Flag indicating whether debug mode is on.  This can be set on the command line. */
+int debug_flag = 0;
+
+/* Flag indicating whether a tty should be allocated */
+int tty_flag = 0;
+int no_tty_flag = 0;
+int force_tty_flag = 0;
+
+/* don't exec a shell */
+int no_shell_flag = 0;
+
+/*
+ * Flag indicating that nothing should be read from stdin.  This can be set
+ * on the command line.
+ */
+int stdin_null_flag = 0;
+
+/*
+ * Flag indicating that ssh should fork after authentication.  This is useful
+ * so that the pasphrase can be entered manually, and then ssh goes to the
+ * background.
+ */
+int fork_after_authentication_flag = 0;
+
+/*
+ * General data structure for command line options and options configurable
+ * in configuration files.  See readconf.h.
+ */
+Options options;
+
+/* optional user configfile */
+char *config = NULL;
+
+/*
+ * Name of the host we are connecting to.  This is the name given on the
+ * command line, or the HostName specified for the user-supplied name in a
+ * configuration file.
+ */
+char *host;
+
+/* socket address the host resolves to */
+struct sockaddr_storage hostaddr;
+
+/* Private host keys. */
+struct {
+       Key     **keys;
+       int     nkeys;
+} sensitive_data;
+
+/* Original real UID. */
+uid_t original_real_uid;
+
+/* command to be executed */
+Buffer command;
+
+/* Should we execute a command or invoke a subsystem? */
+int subsystem_flag = 0;
+
+/* Prints a help message to the user.  This function never returns. */
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: %s [options] host [command]\n", __progname);
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "  -l user     Log in using this user name.\n");
+       fprintf(stderr, "  -n          Redirect input from " _PATH_DEVNULL ".\n");
+       fprintf(stderr, "  -F config   Config file (default: ~/%s).\n",
+            _PATH_SSH_USER_CONFFILE);
+       fprintf(stderr, "  -A          Enable authentication agent forwarding.\n");
+       fprintf(stderr, "  -a          Disable authentication agent forwarding (default).\n");
+#ifdef AFS
+       fprintf(stderr, "  -k          Disable Kerberos ticket and AFS token forwarding.\n");
+#endif                         /* AFS */
+       fprintf(stderr, "  -X          Enable X11 connection forwarding.\n");
+       fprintf(stderr, "  -x          Disable X11 connection forwarding (default).\n");
+       fprintf(stderr, "  -i file     Identity for public key authentication "
+           "(default: ~/.ssh/identity)\n");
+#ifdef SMARTCARD
+       fprintf(stderr, "  -I reader   Set smartcard reader.\n");
+#endif
+       fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");
+       fprintf(stderr, "  -T          Do not allocate a tty.\n");
+       fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
+       fprintf(stderr, "              Multiple -v increases verbosity.\n");
+       fprintf(stderr, "  -V          Display version number only.\n");
+       fprintf(stderr, "  -P          Don't allocate a privileged port.\n");
+       fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");
+       fprintf(stderr, "  -f          Fork into background after authentication.\n");
+       fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");
+
+       fprintf(stderr, "  -c cipher   Select encryption algorithm\n");
+       fprintf(stderr, "  -m macs     Specify MAC algorithms for protocol version 2.\n");
+       fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\n");
+       fprintf(stderr, "  -L listen-port:host:port   Forward local port to remote address\n");
+       fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
+       fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);
+       fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
+       fprintf(stderr, "  -D port     Enable dynamic application-level port forwarding.\n");
+       fprintf(stderr, "  -C          Enable compression.\n");
+       fprintf(stderr, "  -N          Do not execute a shell or command.\n");
+       fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
+       fprintf(stderr, "  -1          Force protocol version 1.\n");
+       fprintf(stderr, "  -2          Force protocol version 2.\n");
+       fprintf(stderr, "  -4          Use IPv4 only.\n");
+       fprintf(stderr, "  -6          Use IPv6 only.\n");
+       fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");
+       fprintf(stderr, "  -s          Invoke command (mandatory) as SSH2 subsystem.\n");
+       fprintf(stderr, "  -b addr     Local IP address.\n");
+       exit(1);
+}
+
+/*
+ * Connects to the given host using rsh (or prints an error message and exits
+ * if rsh is not available).  This function never returns.
+ */
+static void
+rsh_connect(char *host, char *user, Buffer * command)
+{
+       char *args[10];
+       int i;
+
+       log("Using rsh.  WARNING: Connection will not be encrypted.");
+       /* Build argument list for rsh. */
+       i = 0;
+       args[i++] = _PATH_RSH;
+       /* host may have to come after user on some systems */
+       args[i++] = host;
+       if (user) {
+               args[i++] = "-l";
+               args[i++] = user;
+       }
+       if (buffer_len(command) > 0) {
+               buffer_append(command, "\0", 1);
+               args[i++] = buffer_ptr(command);
+       }
+       args[i++] = NULL;
+       if (debug_flag) {
+               for (i = 0; args[i]; i++) {
+                       if (i != 0)
+                               fprintf(stderr, " ");
+                       fprintf(stderr, "%s", args[i]);
+               }
+               fprintf(stderr, "\n");
+       }
+       execv(_PATH_RSH, args);
+       perror(_PATH_RSH);
+       exit(1);
+}
+
+static int ssh_session(void);
+static int ssh_session2(void);
+static void load_public_identity_files(void);
+
+/*
+ * Main program for the ssh client.
+ */
+int
+main(int ac, char **av)
+{
+       int i, opt, exit_status, cerr;
+       u_short fwd_port, fwd_host_port;
+       char sfwd_port[6], sfwd_host_port[6];
+       char *p, *cp, buf[256];
+       struct stat st;
+       struct passwd *pw;
+       int dummy;
+       uid_t original_effective_uid;
+       extern int optind, optreset;
+       extern char *optarg;
+
+       __progname = get_progname(av[0]);
+       init_rng();
+
+       /*
+        * Save the original real uid.  It will be needed later (uid-swapping
+        * may clobber the real uid).
+        */
+       original_real_uid = getuid();
+       original_effective_uid = geteuid();
+
+#ifdef HAVE_SETRLIMIT
+       /* If we are installed setuid root be careful to not drop core. */
+       if (original_real_uid != original_effective_uid) {
+               struct rlimit rlim;
+               rlim.rlim_cur = rlim.rlim_max = 0;
+               if (setrlimit(RLIMIT_CORE, &rlim) < 0)
+                       fatal("setrlimit failed: %.100s", strerror(errno));
+       }
+#endif
+       /* Get user data. */
+       pw = getpwuid(original_real_uid);
+       if (!pw) {
+               log("You don't exist, go away!");
+               exit(1);
+       }
+       /* Take a copy of the returned structure. */
+       pw = pwcopy(pw);
+
+       /*
+        * Use uid-swapping to give up root privileges for the duration of
+        * option processing.  We will re-instantiate the rights when we are
+        * ready to create the privileged port, and will permanently drop
+        * them when the port has been created (actually, when the connection
+        * has been made, as we may need to create the port several times).
+        */
+       temporarily_use_uid(pw);
+
+       /*
+        * Set our umask to something reasonable, as some files are created
+        * with the default umask.  This will make them world-readable but
+        * writable only by the owner, which is ok for all files for which we
+        * don't set the modes explicitly.
+        */
+       umask(022);
+
+       /* Initialize option structure to indicate that no values have been set. */
+       initialize_options(&options);
+
+       /* Parse command-line arguments. */
+       host = NULL;
+
+again:
+       while ((opt = getopt(ac, av,
+           "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {
+               switch (opt) {
+               case '1':
+                       options.protocol = SSH_PROTO_1;
+                       break;
+               case '2':
+                       options.protocol = SSH_PROTO_2;
+                       break;
+               case '4':
+                       IPv4or6 = AF_INET;
+                       break;
+               case '6':
+                       IPv4or6 = AF_INET6;
+                       break;
+               case 'n':
+                       stdin_null_flag = 1;
+                       break;
+               case 'f':
+                       fork_after_authentication_flag = 1;
+                       stdin_null_flag = 1;
+                       break;
+               case 'x':
+                       options.forward_x11 = 0;
+                       break;
+               case 'X':
+                       options.forward_x11 = 1;
+                       break;
+               case 'g':
+                       options.gateway_ports = 1;
+                       break;
+               case 'P':
+                       options.use_privileged_port = 0;
+                       break;
+               case 'a':
+                       options.forward_agent = 0;
+                       break;
+               case 'A':
+                       options.forward_agent = 1;
+                       break;
+#ifdef AFS
+               case 'k':
+                       options.kerberos_tgt_passing = 0;
+                       options.afs_token_passing = 0;
+                       break;
+#endif
+               case 'i':
+                       if (stat(optarg, &st) < 0) {
+                               fprintf(stderr, "Warning: Identity file %s "
+                                   "does not exist.\n", optarg);
+                               break;
+                       }
+                       if (options.num_identity_files >=
+                           SSH_MAX_IDENTITY_FILES)
+                               fatal("Too many identity files specified "
+                                   "(max %d)", SSH_MAX_IDENTITY_FILES);
+                       options.identity_files[options.num_identity_files++] =
+                           xstrdup(optarg);
+                       break;
+               case 'I':
+#ifdef SMARTCARD
+                       options.smartcard_device = xstrdup(optarg);
+#else
+                       fprintf(stderr, "no support for smartcards.\n");
+#endif
+                       break;
+               case 't':
+                       if (tty_flag)
+                               force_tty_flag = 1;
+                       tty_flag = 1;
+                       break;
+               case 'v':
+                       if (0 == debug_flag) {
+                               debug_flag = 1;
+                               options.log_level = SYSLOG_LEVEL_DEBUG1;
+                       } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
+                               options.log_level++;
+                               break;
+                       } else
+                               fatal("Too high debugging level.");
+                       /* fallthrough */
+               case 'V':
+                       fprintf(stderr,
+                           "%s, SSH protocols %d.%d/%d.%d, OpenSSL 0x%8.8lx\n",
+                           SSH_VERSION,
+                           PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
+                           PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2,
+                           SSLeay());
+                       if (opt == 'V')
+                               exit(0);
+                       break;
+               case 'q':
+                       options.log_level = SYSLOG_LEVEL_QUIET;
+                       break;
+               case 'e':
+                       if (optarg[0] == '^' && optarg[2] == 0 &&
+                           (u_char) optarg[1] >= 64 &&
+                           (u_char) optarg[1] < 128)
+                               options.escape_char = (u_char) optarg[1] & 31;
+                       else if (strlen(optarg) == 1)
+                               options.escape_char = (u_char) optarg[0];
+                       else if (strcmp(optarg, "none") == 0)
+                               options.escape_char = SSH_ESCAPECHAR_NONE;
+                       else {
+                               fprintf(stderr, "Bad escape character '%s'.\n",
+                                   optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'c':
+                       if (ciphers_valid(optarg)) {
+                               /* SSH2 only */
+                               options.ciphers = xstrdup(optarg);
+                               options.cipher = SSH_CIPHER_ILLEGAL;
+                       } else {
+                               /* SSH1 only */
+                               options.cipher = cipher_number(optarg);
+                               if (options.cipher == -1) {
+                                       fprintf(stderr,
+                                           "Unknown cipher type '%s'\n",
+                                           optarg);
+                                       exit(1);
+                               }
+                               if (options.cipher == SSH_CIPHER_3DES)
+                                       options.ciphers = "3des-cbc";
+                               else if (options.cipher == SSH_CIPHER_BLOWFISH)
+                                       options.ciphers = "blowfish-cbc";
+                               else
+                                       options.ciphers = (char *)-1;
+                       }
+                       break;
+               case 'm':
+                       if (mac_valid(optarg))
+                               options.macs = xstrdup(optarg);
+                       else {
+                               fprintf(stderr, "Unknown mac type '%s'\n",
+                                   optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'p':
+                       options.port = a2port(optarg);
+                       if (options.port == 0) {
+                               fprintf(stderr, "Bad port '%s'\n", optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'l':
+                       options.user = optarg;
+                       break;
+
+               case 'L':
+               case 'R':
+                       if (sscanf(optarg, "%5[0-9]:%255[^:]:%5[0-9]",
+                           sfwd_port, buf, sfwd_host_port) != 3 &&
+                           sscanf(optarg, "%5[0-9]/%255[^/]/%5[0-9]",
+                           sfwd_port, buf, sfwd_host_port) != 3) {
+                               fprintf(stderr,
+                                   "Bad forwarding specification '%s'\n",
+                                   optarg);
+                               usage();
+                               /* NOTREACHED */
+                       }
+                       if ((fwd_port = a2port(sfwd_port)) == 0 ||
+                           (fwd_host_port = a2port(sfwd_host_port)) == 0) {
+                               fprintf(stderr,
+                                   "Bad forwarding port(s) '%s'\n", optarg);
+                               exit(1);
+                       }
+                       if (opt == 'L')
+                               add_local_forward(&options, fwd_port, buf,
+                                   fwd_host_port);
+                       else if (opt == 'R')
+                               add_remote_forward(&options, fwd_port, buf,
+                                    fwd_host_port);
+                       break;
+
+               case 'D':
+                       fwd_port = a2port(optarg);
+                       if (fwd_port == 0) {
+                               fprintf(stderr, "Bad dynamic port '%s'\n",
+                                   optarg);
+                               exit(1);
+                       }
+                       add_local_forward(&options, fwd_port, "socks4", 0);
+                       break;
+
+               case 'C':
+                       options.compression = 1;
+                       break;
+               case 'N':
+                       no_shell_flag = 1;
+                       no_tty_flag = 1;
+                       break;
+               case 'T':
+                       no_tty_flag = 1;
+                       break;
+               case 'o':
+                       dummy = 1;
+                       if (process_config_line(&options, host ? host : "",
+                           optarg, "command-line", 0, &dummy) != 0)
+                               exit(1);
+                       break;
+               case 's':
+                       subsystem_flag = 1;
+                       break;
+               case 'b':
+                       options.bind_address = optarg;
+                       break;
+               case 'F':
+                       config = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       ac -= optind;
+       av += optind;
+
+       if (ac > 0 && !host && **av != '-') {
+               if (strchr(*av, '@')) {
+                       p = xstrdup(*av);
+                       cp = strchr(p, '@');
+                       if (cp == NULL || cp == p)
+                               usage();
+                       options.user = p;
+                       *cp = '\0';
+                       host = ++cp;
+               } else
+                       host = *av;
+               ac--, av++;
+               if (ac > 0) {
+                       optind = 0;
+                       optreset = 1;
+                       goto again;
+               }
+       }
+
+       /* Check that we got a host name. */
+       if (!host)
+               usage();
+
+       SSLeay_add_all_algorithms();
+       ERR_load_crypto_strings();
+       channel_set_af(IPv4or6);
+
+       /* Initialize the command to execute on remote host. */
+       buffer_init(&command);
+
+       /*
+        * Save the command to execute on the remote host in a buffer. There
+        * is no limit on the length of the command, except by the maximum
+        * packet size.  Also sets the tty flag if there is no command.
+        */
+       if (!ac) {
+               /* No command specified - execute shell on a tty. */
+               tty_flag = 1;
+               if (subsystem_flag) {
+                       fprintf(stderr,
+                           "You must specify a subsystem to invoke.\n");
+                       usage();
+               }
+       } else {
+               /* A command has been specified.  Store it into the buffer. */
+               for (i = 0; i < ac; i++) {
+                       if (i)
+                               buffer_append(&command, " ", 1);
+                       buffer_append(&command, av[i], strlen(av[i]));
+               }
+       }
+
+       /* Cannot fork to background if no command. */
+       if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag)
+               fatal("Cannot fork into background without a command to execute.");
+
+       /* Allocate a tty by default if no command specified. */
+       if (buffer_len(&command) == 0)
+               tty_flag = 1;
+
+       /* Force no tty*/
+       if (no_tty_flag)
+               tty_flag = 0;
+       /* Do not allocate a tty if stdin is not a tty. */
+       if (!isatty(fileno(stdin)) && !force_tty_flag) {
+               if (tty_flag)
+                       log("Pseudo-terminal will not be allocated because stdin is not a terminal.");
+               tty_flag = 0;
+       }
+
+       /*
+        * Initialize "log" output.  Since we are the client all output
+        * actually goes to stderr.
+        */
+       log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
+           SYSLOG_FACILITY_USER, 1);
+
+       /*
+        * Read per-user configuration file.  Ignore the system wide config
+        * file if the user specifies a config file on the command line.
+        */
+       if (config != NULL) {
+               if (!read_config_file(config, host, &options))
+                       fatal("Can't open user config file %.100s: "
+                           "%.100s", config, strerror(errno));
+       } else  {
+               snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
+                   _PATH_SSH_USER_CONFFILE);
+               (void)read_config_file(buf, host, &options);
+
+               /* Read systemwide configuration file after use config. */
+               (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
+       }
+
+       /* Fill configuration defaults. */
+       fill_default_options(&options);
+
+       /* reinit */
+       log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
+
+       seed_rng();
+
+       if (options.user == NULL)
+               options.user = xstrdup(pw->pw_name);
+
+       if (options.hostname != NULL)
+               host = options.hostname;
+
+       /* Disable rhosts authentication if not running as root. */
+#ifdef HAVE_CYGWIN
+       /* Ignore uid if running under Windows */
+       if (!options.use_privileged_port) {
+#else
+       if (original_effective_uid != 0 || !options.use_privileged_port) {
+#endif
+               debug("Rhosts Authentication disabled, "
+                   "originating port will not be trusted.");
+               options.rhosts_authentication = 0;
+       }
+       /*
+        * If using rsh has been selected, exec it now (without trying
+        * anything else).  Note that we must release privileges first.
+        */
+       if (options.use_rsh) {
+               /*
+                * Restore our superuser privileges.  This must be done
+                * before permanently setting the uid.
+                */
+               restore_uid();
+
+               /* Switch to the original uid permanently. */
+               permanently_set_uid(pw);
+
+               /* Execute rsh. */
+               rsh_connect(host, options.user, &command);
+               fatal("rsh_connect returned");
+       }
+       /* Restore our superuser privileges. */
+       restore_uid();
+
+       /* Open a connection to the remote host. */
+
+       cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6,
+           options.connection_attempts,
+           original_effective_uid != 0 || !options.use_privileged_port,
+           pw, options.proxy_command);
+
+       /*
+        * If we successfully made the connection, load the host private key
+        * in case we will need it later for combined rsa-rhosts
+        * authentication. This must be done before releasing extra
+        * privileges, because the file is only readable by root.
+        */
+       sensitive_data.nkeys = 0;
+       sensitive_data.keys = NULL;
+       if (!cerr && (options.rhosts_rsa_authentication ||
+           options.hostbased_authentication)) {
+               sensitive_data.nkeys = 3;
+               sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key));
+               sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
+                   _PATH_HOST_KEY_FILE, "", NULL);
+               sensitive_data.keys[1] = key_load_private_type(KEY_DSA,
+                   _PATH_HOST_DSA_KEY_FILE, "", NULL);
+               sensitive_data.keys[2] = key_load_private_type(KEY_RSA,
+                   _PATH_HOST_RSA_KEY_FILE, "", NULL);
+       }
+       /*
+        * Get rid of any extra privileges that we may have.  We will no
+        * longer need them.  Also, extra privileges could make it very hard
+        * to read identity files and other non-world-readable files from the
+        * user's home directory if it happens to be on a NFS volume where
+        * root is mapped to nobody.
+        */
+
+       /*
+        * Note that some legacy systems need to postpone the following call
+        * to permanently_set_uid() until the private hostkey is destroyed
+        * with RSA_free().  Otherwise the calling user could ptrace() the
+        * process, read the private hostkey and impersonate the host.
+        * OpenBSD does not allow ptracing of setuid processes.
+        */
+       permanently_set_uid(pw);
+
+       /*
+        * Now that we are back to our own permissions, create ~/.ssh
+        * directory if it doesn\'t already exist.
+        */
+       snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
+       if (stat(buf, &st) < 0)
+               if (mkdir(buf, 0700) < 0)
+                       error("Could not create directory '%.200s'.", buf);
+
+       /* Check if the connection failed, and try "rsh" if appropriate. */
+       if (cerr) {
+               if (!options.fallback_to_rsh)
+                       exit(1);
+               if (options.port != 0)
+                       log("Secure connection to %.100s on port %hu refused; "
+                           "reverting to insecure method",
+                           host, options.port);
+               else
+                       log("Secure connection to %.100s refused; "
+                           "reverting to insecure method.", host);
+
+               rsh_connect(host, options.user, &command);
+               fatal("rsh_connect returned");
+       }
+       /* load options.identity_files */
+       load_public_identity_files();
+
+       /* Expand ~ in known host file names. */
+       /* XXX mem-leaks: */
+       options.system_hostfile =
+           tilde_expand_filename(options.system_hostfile, original_real_uid);
+       options.user_hostfile =
+           tilde_expand_filename(options.user_hostfile, original_real_uid);
+       options.system_hostfile2 =
+           tilde_expand_filename(options.system_hostfile2, original_real_uid);
+       options.user_hostfile2 =
+           tilde_expand_filename(options.user_hostfile2, original_real_uid);
+
+       signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
+
+       /* Log into the remote system.  This never returns if the login fails. */
+       ssh_login(sensitive_data.keys, sensitive_data.nkeys,
+           host, (struct sockaddr *)&hostaddr, pw);
+
+       /* We no longer need the private host keys.  Clear them now. */
+       if (sensitive_data.nkeys != 0) {
+               for (i = 0; i < sensitive_data.nkeys; i++) {
+                       if (sensitive_data.keys[i] != NULL) {
+                               /* Destroys contents safely */
+                               debug3("clear hostkey %d", i);
+                               key_free(sensitive_data.keys[i]);
+                               sensitive_data.keys[i] = NULL;
+                       }
+               }
+               xfree(sensitive_data.keys);
+       }
+       for (i = 0; i < options.num_identity_files; i++) {
+               if (options.identity_files[i]) {
+                       xfree(options.identity_files[i]);
+                       options.identity_files[i] = NULL;
+               }
+               if (options.identity_keys[i]) {
+                       key_free(options.identity_keys[i]);
+                       options.identity_keys[i] = NULL;
+               }
+       }
+
+       exit_status = compat20 ? ssh_session2() : ssh_session();
+       packet_close();
+       return exit_status;
+}
+
+static void
+x11_get_proto(char *proto, int proto_len, char *data, int data_len)
+{
+       char line[512];
+       FILE *f;
+       int got_data = 0, i;
+
+       if (options.xauth_location) {
+               /* Try to get Xauthority information for the display. */
+               snprintf(line, sizeof line, "%.100s list %.200s 2>" _PATH_DEVNULL,
+                   options.xauth_location, getenv("DISPLAY"));
+               f = popen(line, "r");
+               if (f && fgets(line, sizeof(line), f) &&
+                   sscanf(line, "%*s %s %s", proto, data) == 2)
+                       got_data = 1;
+               if (f)
+                       pclose(f);
+       }
+       /*
+        * If we didn't get authentication data, just make up some
+        * data.  The forwarding code will check the validity of the
+        * response anyway, and substitute this data.  The X11
+        * server, however, will ignore this fake data and use
+        * whatever authentication mechanisms it was using otherwise
+        * for the local connection.
+        */
+       if (!got_data) {
+               u_int32_t rand = 0;
+
+               strlcpy(proto, "MIT-MAGIC-COOKIE-1", proto_len);
+               for (i = 0; i < 16; i++) {
+                       if (i % 4 == 0)
+                               rand = arc4random();
+                       snprintf(data + 2 * i, data_len - 2 * i, "%02x", rand & 0xff);
+                       rand >>= 8;
+               }
+       }
+}
+
+static void
+ssh_init_forwarding(void)
+{
+       int success = 0;
+       int i;
+
+       /* Initiate local TCP/IP port forwardings. */
+       for (i = 0; i < options.num_local_forwards; i++) {
+               debug("Connections to local port %d forwarded to remote address %.200s:%d",
+                   options.local_forwards[i].port,
+                   options.local_forwards[i].host,
+                   options.local_forwards[i].host_port);
+               success += channel_request_local_forwarding(
+                   options.local_forwards[i].port,
+                   options.local_forwards[i].host,
+                   options.local_forwards[i].host_port,
+                   options.gateway_ports);
+       }
+       if (i > 0 && success == 0)
+               error("Could not request local forwarding.");
+
+       /* Initiate remote TCP/IP port forwardings. */
+       for (i = 0; i < options.num_remote_forwards; i++) {
+               debug("Connections to remote port %d forwarded to local address %.200s:%d",
+                   options.remote_forwards[i].port,
+                   options.remote_forwards[i].host,
+                   options.remote_forwards[i].host_port);
+               channel_request_remote_forwarding(
+                   options.remote_forwards[i].port,
+                   options.remote_forwards[i].host,
+                   options.remote_forwards[i].host_port);
+       }
+}
+
+static void
+check_agent_present(void)
+{
+       if (options.forward_agent) {
+               /* Clear agent forwarding if we don\'t have an agent. */
+               int authfd = ssh_get_authentication_socket();
+               if (authfd < 0)
+                       options.forward_agent = 0;
+               else
+                       ssh_close_authentication_socket(authfd);
+       }
+}
+
+static int
+ssh_session(void)
+{
+       int type;
+       int plen;
+       int interactive = 0;
+       int have_tty = 0;
+       struct winsize ws;
+       char *cp;
+
+       /* Enable compression if requested. */
+       if (options.compression) {
+               debug("Requesting compression at level %d.", options.compression_level);
+
+               if (options.compression_level < 1 || options.compression_level > 9)
+                       fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
+
+               /* Send the request. */
+               packet_start(SSH_CMSG_REQUEST_COMPRESSION);
+               packet_put_int(options.compression_level);
+               packet_send();
+               packet_write_wait();
+               type = packet_read(&plen);
+               if (type == SSH_SMSG_SUCCESS)
+                       packet_start_compression(options.compression_level);
+               else if (type == SSH_SMSG_FAILURE)
+                       log("Warning: Remote host refused compression.");
+               else
+                       packet_disconnect("Protocol error waiting for compression response.");
+       }
+       /* Allocate a pseudo tty if appropriate. */
+       if (tty_flag) {
+               debug("Requesting pty.");
+
+               /* Start the packet. */
+               packet_start(SSH_CMSG_REQUEST_PTY);
+
+               /* Store TERM in the packet.  There is no limit on the
+                  length of the string. */
+               cp = getenv("TERM");
+               if (!cp)
+                       cp = "";
+               packet_put_cstring(cp);
+
+               /* Store window size in the packet. */
+               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
+                       memset(&ws, 0, sizeof(ws));
+               packet_put_int(ws.ws_row);
+               packet_put_int(ws.ws_col);
+               packet_put_int(ws.ws_xpixel);
+               packet_put_int(ws.ws_ypixel);
+
+               /* Store tty modes in the packet. */
+               tty_make_modes(fileno(stdin), NULL);
+
+               /* Send the packet, and wait for it to leave. */
+               packet_send();
+               packet_write_wait();
+
+               /* Read response from the server. */
+               type = packet_read(&plen);
+               if (type == SSH_SMSG_SUCCESS) {
+                       interactive = 1;
+                       have_tty = 1;
+               } else if (type == SSH_SMSG_FAILURE)
+                       log("Warning: Remote host failed or refused to allocate a pseudo tty.");
+               else
+                       packet_disconnect("Protocol error waiting for pty request response.");
+       }
+       /* Request X11 forwarding if enabled and DISPLAY is set. */
+       if (options.forward_x11 && getenv("DISPLAY") != NULL) {
+               char proto[512], data[512];
+               /* Get reasonable local authentication information. */
+               x11_get_proto(proto, sizeof proto, data, sizeof data);
+               /* Request forwarding with authentication spoofing. */
+               debug("Requesting X11 forwarding with authentication spoofing.");
+               x11_request_forwarding_with_spoofing(0, proto, data);
+
+               /* Read response from the server. */
+               type = packet_read(&plen);
+               if (type == SSH_SMSG_SUCCESS) {
+                       interactive = 1;
+               } else if (type == SSH_SMSG_FAILURE) {
+                       log("Warning: Remote host denied X11 forwarding.");
+               } else {
+                       packet_disconnect("Protocol error waiting for X11 forwarding");
+               }
+       }
+       /* Tell the packet module whether this is an interactive session. */
+       packet_set_interactive(interactive);
+
+       /* Request authentication agent forwarding if appropriate. */
+       check_agent_present();
+
+       if (options.forward_agent) {
+               debug("Requesting authentication agent forwarding.");
+               auth_request_forwarding();
+
+               /* Read response from the server. */
+               type = packet_read(&plen);
+               packet_integrity_check(plen, 0, type);
+               if (type != SSH_SMSG_SUCCESS)
+                       log("Warning: Remote host denied authentication agent forwarding.");
+       }
+
+       /* Initiate port forwardings. */
+       ssh_init_forwarding();
+
+       /* If requested, let ssh continue in the background. */
+       if (fork_after_authentication_flag)
+               if (daemon(1, 1) < 0)
+                       fatal("daemon() failed: %.200s", strerror(errno));
+
+       /*
+        * If a command was specified on the command line, execute the
+        * command now. Otherwise request the server to start a shell.
+        */
+       if (buffer_len(&command) > 0) {
+               int len = buffer_len(&command);
+               if (len > 900)
+                       len = 900;
+               debug("Sending command: %.*s", len, buffer_ptr(&command));
+               packet_start(SSH_CMSG_EXEC_CMD);
+               packet_put_string(buffer_ptr(&command), buffer_len(&command));
+               packet_send();
+               packet_write_wait();
+       } else {
+               debug("Requesting shell.");
+               packet_start(SSH_CMSG_EXEC_SHELL);
+               packet_send();
+               packet_write_wait();
+       }
+
+       /* Enter the interactive session. */
+       return client_loop(have_tty, tty_flag ?
+           options.escape_char : SSH_ESCAPECHAR_NONE, 0);
+}
+
+static void
+client_subsystem_reply(int type, int plen, void *ctxt)
+{
+       int id, len;
+
+       id = packet_get_int();
+       len = buffer_len(&command);
+       if (len > 900)
+               len = 900;
+       packet_done();
+       if (type == SSH2_MSG_CHANNEL_FAILURE)
+               fatal("Request for subsystem '%.*s' failed on channel %d",
+                   len, buffer_ptr(&command), id);
+}
+
+/* request pty/x11/agent/tcpfwd/shell for channel */
+static void
+ssh_session2_setup(int id, void *arg)
+{
+       int len;
+       int interactive = 0;
+       struct termios tio;
+
+       debug("ssh_session2_setup: id %d", id);
+
+       if (tty_flag) {
+               struct winsize ws;
+               char *cp;
+               cp = getenv("TERM");
+               if (!cp)
+                       cp = "";
+               /* Store window size in the packet. */
+               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
+                       memset(&ws, 0, sizeof(ws));
+
+               channel_request_start(id, "pty-req", 0);
+               packet_put_cstring(cp);
+               packet_put_int(ws.ws_col);
+               packet_put_int(ws.ws_row);
+               packet_put_int(ws.ws_xpixel);
+               packet_put_int(ws.ws_ypixel);
+               tio = get_saved_tio();
+               tty_make_modes(/*ignored*/ 0, &tio);
+               packet_send();
+               interactive = 1;
+               /* XXX wait for reply */
+       }
+       if (options.forward_x11 &&
+           getenv("DISPLAY") != NULL) {
+               char proto[512], data[512];
+               /* Get reasonable local authentication information. */
+               x11_get_proto(proto, sizeof proto, data, sizeof data);
+               /* Request forwarding with authentication spoofing. */
+               debug("Requesting X11 forwarding with authentication spoofing.");
+               x11_request_forwarding_with_spoofing(id, proto, data);
+               interactive = 1;
+               /* XXX wait for reply */
+       }
+
+       check_agent_present();
+       if (options.forward_agent) {
+               debug("Requesting authentication agent forwarding.");
+               channel_request_start(id, "auth-agent-req@openssh.com", 0);
+               packet_send();
+       }
+
+       len = buffer_len(&command);
+       if (len > 0) {
+               if (len > 900)
+                       len = 900;
+               if (subsystem_flag) {
+                       debug("Sending subsystem: %.*s", len, buffer_ptr(&command));
+                       channel_request_start(id, "subsystem", /*want reply*/ 1);
+                       /* register callback for reply */
+                       /* XXX we asume that client_loop has already been called */
+                       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
+                       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
+               } else {
+                       debug("Sending command: %.*s", len, buffer_ptr(&command));
+                       channel_request_start(id, "exec", 0);
+               }
+               packet_put_string(buffer_ptr(&command), buffer_len(&command));
+               packet_send();
+       } else {
+               channel_request(id, "shell", 0);
+       }
+       /* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
+
+       /* register different callback, etc. XXX */
+       packet_set_interactive(interactive);
+}
+
+/* open new channel for a session */
+static int
+ssh_session2_open(void)
+{
+       Channel *c;
+       int window, packetmax, in, out, err;
+
+       if (stdin_null_flag) {
+               in = open(_PATH_DEVNULL, O_RDONLY);
+       } else {
+               in = dup(STDIN_FILENO);
+       }
+       out = dup(STDOUT_FILENO);
+       err = dup(STDERR_FILENO);
+
+       if (in < 0 || out < 0 || err < 0)
+               fatal("dup() in/out/err failed");
+
+       /* enable nonblocking unless tty */
+       if (!isatty(in))
+               set_nonblock(in);
+       if (!isatty(out))
+               set_nonblock(out);
+       if (!isatty(err))
+               set_nonblock(err);
+
+       window = CHAN_SES_WINDOW_DEFAULT;
+       packetmax = CHAN_SES_PACKET_DEFAULT;
+       if (!tty_flag) {
+               window *= 2;
+               packetmax *=2;
+       }
+       c = channel_new(
+           "session", SSH_CHANNEL_OPENING, in, out, err,
+           window, packetmax, CHAN_EXTENDED_WRITE,
+           xstrdup("client-session"), /*nonblock*/0);
+       if (c == NULL)
+               fatal("ssh_session2_open: channel_new failed");
+
+       debug3("ssh_session2_open: channel_new: %d", c->self);
+
+       channel_send_open(c->self);
+       if (!no_shell_flag)
+               channel_register_callback(c->self,
+                    SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
+                    ssh_session2_setup, (void *)0);
+
+       return c->self;
+}
+
+static int
+ssh_session2(void)
+{
+       int id = -1;
+
+       /* XXX should be pre-session */
+       ssh_init_forwarding();
+
+       if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
+               id = ssh_session2_open();
+
+       /* If requested, let ssh continue in the background. */
+       if (fork_after_authentication_flag)
+               if (daemon(1, 1) < 0)
+                       fatal("daemon() failed: %.200s", strerror(errno));
+
+       return client_loop(tty_flag, tty_flag ?
+           options.escape_char : SSH_ESCAPECHAR_NONE, id);
+}
+
+static void
+load_public_identity_files(void)
+{
+       char *filename;
+       Key *public;
+       int i = 0;
+
+#ifdef SMARTCARD
+       if (options.smartcard_device != NULL &&
+           options.num_identity_files + 1 < SSH_MAX_IDENTITY_FILES &&
+           (public = sc_get_key(options.smartcard_device)) != NULL ) {
+               Key *new;
+
+               if (options.num_identity_files + 2 > SSH_MAX_IDENTITY_FILES)
+                       options.num_identity_files = SSH_MAX_IDENTITY_FILES - 2;
+               memmove(&options.identity_files[2], &options.identity_files[0],
+                   sizeof(char *) * options.num_identity_files);
+               options.num_identity_files += 2;
+               i = 2;
+
+               /* XXX ssh1 vs ssh2 */
+               new = key_new(KEY_RSA);
+               new->flags = KEY_FLAG_EXT;
+               BN_copy(new->rsa->n, public->rsa->n);
+               BN_copy(new->rsa->e, public->rsa->e);
+               RSA_set_method(new->rsa, sc_get_engine());
+               options.identity_keys[0] = new;
+               options.identity_files[0] = xstrdup("smartcard rsa key");;
+
+               new = key_new(KEY_RSA1);
+               new->flags = KEY_FLAG_EXT;
+               BN_copy(new->rsa->n, public->rsa->n);
+               BN_copy(new->rsa->e, public->rsa->e);
+               RSA_set_method(new->rsa, sc_get_engine());
+               options.identity_keys[1] = new;
+               options.identity_files[1] = xstrdup("smartcard rsa1 key");
+
+               key_free(public);
+       }
+#endif /* SMARTCARD */
+       for (; i < options.num_identity_files; i++) {
+               filename = tilde_expand_filename(options.identity_files[i],
+                   original_real_uid);
+               public = key_load_public(filename, NULL);
+               debug("identity file %s type %d", filename,
+                   public ? public->type : -1);
+               xfree(options.identity_files[i]);
+               options.identity_files[i] = filename;
+               options.identity_keys[i] = public;
+       }
+}
diff --git a/openssh/ssh.h b/openssh/ssh.h
new file mode 100644 (file)
index 0000000..383c7fe
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: ssh.h,v 1.63 2001/05/24 18:57:53 stevesk Exp $"); */
+
+#ifndef SSH_H
+#define SSH_H
+
+#include <netinet/in.h> /* For struct sockaddr_in */
+#include <pwd.h> /* For struct pw */
+#include <stdarg.h> /* For va_list */
+#include <syslog.h> /* For LOG_AUTH and friends */
+#include <sys/socket.h> /* For struct sockaddr_storage */
+#include "openbsd-compat/fake-socket.h" /* For struct sockaddr_storage */
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+/* Cipher used for encrypting authentication files. */
+#define SSH_AUTHFILE_CIPHER    SSH_CIPHER_3DES
+
+/* Default port number. */
+#define SSH_DEFAULT_PORT       22
+
+/* Maximum number of TCP/IP ports forwarded per direction. */
+#define SSH_MAX_FORWARDS_PER_DIRECTION 100
+
+/*
+ * Maximum number of RSA authentication identity files that can be specified
+ * in configuration files or on the command line.
+ */
+#define SSH_MAX_IDENTITY_FILES         100
+
+/*
+ * Major protocol version.  Different version indicates major incompatiblity
+ * that prevents communication.
+ *
+ * Minor protocol version.  Different version indicates minor incompatibility
+ * that does not prevent interoperation.
+ */
+#define PROTOCOL_MAJOR_1       1
+#define PROTOCOL_MINOR_1       5
+
+/* We support both SSH1 and SSH2 */
+#define PROTOCOL_MAJOR_2       2
+#define PROTOCOL_MINOR_2       0
+
+/*
+ * Name for the service.  The port named by this service overrides the
+ * default port if present.
+ */
+#define SSH_SERVICE_NAME       "ssh"
+
+#if defined(USE_PAM) && !defined(SSHD_PAM_SERVICE)
+# define SSHD_PAM_SERVICE       __progname
+#endif
+
+/*
+ * Name of the environment variable containing the pathname of the
+ * authentication socket.
+ */
+#define SSH_AGENTPID_ENV_NAME  "SSH_AGENT_PID"
+
+/*
+ * Name of the environment variable containing the pathname of the
+ * authentication socket.
+ */
+#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
+
+/*
+ * Environment variable for overwriting the default location of askpass
+ */
+#define SSH_ASKPASS_ENV                "SSH_ASKPASS"
+
+/*
+ * Force host key length and server key length to differ by at least this
+ * many bits.  This is to make double encryption with rsaref work.
+ */
+#define SSH_KEY_BITS_RESERVED          128
+
+/*
+ * Length of the session key in bytes.  (Specified as 256 bits in the
+ * protocol.)
+ */
+#define SSH_SESSION_KEY_LENGTH         32
+
+/* Name of Kerberos service for SSH to use. */
+#define KRB4_SERVICE_NAME              "rcmd"
+
+/* Used to identify ``EscapeChar none'' */
+#define SSH_ESCAPECHAR_NONE            -2
+
+#endif                         /* SSH_H */
diff --git a/openssh/ssh1.h b/openssh/ssh1.h
new file mode 100644 (file)
index 0000000..98d1dc9
--- /dev/null
@@ -0,0 +1,89 @@
+/*     $OpenBSD: ssh1.h,v 1.3 2001/05/30 12:55:13 markus Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * Definition of message types.  New values can be added, but old values
+ * should not be removed or without careful consideration of the consequences
+ * for compatibility.  The maximum value is 254; value 255 is reserved for
+ * future extension.
+ */
+/* Message name */                     /* msg code */  /* arguments */
+#define SSH_MSG_NONE                           0       /* no message */
+#define SSH_MSG_DISCONNECT                     1       /* cause (string) */
+#define SSH_SMSG_PUBLIC_KEY                    2       /* ck,msk,srvk,hostk */
+#define SSH_CMSG_SESSION_KEY                   3       /* key (BIGNUM) */
+#define SSH_CMSG_USER                          4       /* user (string) */
+#define SSH_CMSG_AUTH_RHOSTS                   5       /* user (string) */
+#define SSH_CMSG_AUTH_RSA                      6       /* modulus (BIGNUM) */
+#define SSH_SMSG_AUTH_RSA_CHALLENGE            7       /* int (BIGNUM) */
+#define SSH_CMSG_AUTH_RSA_RESPONSE             8       /* int (BIGNUM) */
+#define SSH_CMSG_AUTH_PASSWORD                 9       /* pass (string) */
+#define SSH_CMSG_REQUEST_PTY                   10      /* TERM, tty modes */
+#define SSH_CMSG_WINDOW_SIZE                   11      /* row,col,xpix,ypix */
+#define SSH_CMSG_EXEC_SHELL                    12      /* */
+#define SSH_CMSG_EXEC_CMD                      13      /* cmd (string) */
+#define SSH_SMSG_SUCCESS                       14      /* */
+#define SSH_SMSG_FAILURE                       15      /* */
+#define SSH_CMSG_STDIN_DATA                    16      /* data (string) */
+#define SSH_SMSG_STDOUT_DATA                   17      /* data (string) */
+#define SSH_SMSG_STDERR_DATA                   18      /* data (string) */
+#define SSH_CMSG_EOF                           19      /* */
+#define SSH_SMSG_EXITSTATUS                    20      /* status (int) */
+#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION      21      /* channel (int) */
+#define SSH_MSG_CHANNEL_OPEN_FAILURE           22      /* channel (int) */
+#define SSH_MSG_CHANNEL_DATA                   23      /* ch,data (int,str) */
+#define SSH_MSG_CHANNEL_CLOSE                  24      /* channel (int) */
+#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION     25      /* channel (int) */
+/*      SSH_CMSG_X11_REQUEST_FORWARDING         26         OBSOLETE */
+#define SSH_SMSG_X11_OPEN                      27      /* channel (int) */
+#define SSH_CMSG_PORT_FORWARD_REQUEST          28      /* p,host,hp (i,s,i) */
+#define SSH_MSG_PORT_OPEN                      29      /* ch,h,p (i,s,i) */
+#define SSH_CMSG_AGENT_REQUEST_FORWARDING      30      /* */
+#define SSH_SMSG_AGENT_OPEN                    31      /* port (int) */
+#define SSH_MSG_IGNORE                         32      /* string */
+#define SSH_CMSG_EXIT_CONFIRMATION             33      /* */
+#define SSH_CMSG_X11_REQUEST_FORWARDING                34      /* proto,data (s,s) */
+#define SSH_CMSG_AUTH_RHOSTS_RSA               35      /* user,mod (s,mpi) */
+#define SSH_MSG_DEBUG                          36      /* string */
+#define SSH_CMSG_REQUEST_COMPRESSION           37      /* level 1-9 (int) */
+#define SSH_CMSG_MAX_PACKET_SIZE               38      /* size 4k-1024k (int) */
+#define SSH_CMSG_AUTH_TIS                      39      /* we use this for s/key */
+#define SSH_SMSG_AUTH_TIS_CHALLENGE            40      /* challenge (string) */
+#define SSH_CMSG_AUTH_TIS_RESPONSE             41      /* response (string) */
+#define SSH_CMSG_AUTH_KERBEROS                 42      /* (KTEXT) */
+#define SSH_SMSG_AUTH_KERBEROS_RESPONSE                43      /* (KTEXT) */
+#define SSH_CMSG_HAVE_KERBEROS_TGT             44      /* credentials (s) */
+#define SSH_CMSG_HAVE_AFS_TOKEN                        65      /* token (s) */
+
+/* protocol version 1.5 overloads some version 1.3 message types */
+#define SSH_MSG_CHANNEL_INPUT_EOF      SSH_MSG_CHANNEL_CLOSE
+#define SSH_MSG_CHANNEL_OUTPUT_CLOSE   SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
+
+/*
+ * Authentication methods.  New types can be added, but old types should not
+ * be removed for compatibility.  The maximum allowed value is 31.
+ */
+#define SSH_AUTH_RHOSTS                1
+#define SSH_AUTH_RSA           2
+#define SSH_AUTH_PASSWORD      3
+#define SSH_AUTH_RHOSTS_RSA    4
+#define SSH_AUTH_TIS           5
+#define SSH_AUTH_KERBEROS      6
+#define SSH_PASS_KERBEROS_TGT  7
+                               /* 8 to 15 are reserved */
+#define SSH_PASS_AFS_TOKEN     21
+
+/* Protocol flags.  These are bit masks. */
+#define SSH_PROTOFLAG_SCREEN_NUMBER    1       /* X11 forwarding includes screen */
+#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2       /* forwarding opens contain host */
diff --git a/openssh/ssh2.h b/openssh/ssh2.h
new file mode 100644 (file)
index 0000000..e45aef2
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * draft-ietf-secsh-architecture-05.txt
+ *
+ *   Transport layer protocol:
+ *
+ *     1-19     Transport layer generic (e.g. disconnect, ignore, debug,
+ *              etc)
+ *     20-29    Algorithm negotiation
+ *     30-49    Key exchange method specific (numbers can be reused for
+ *              different authentication methods)
+ *
+ *   User authentication protocol:
+ *
+ *     50-59    User authentication generic
+ *     60-79    User authentication method specific (numbers can be reused
+ *              for different authentication methods)
+ *
+ *   Connection protocol:
+ *
+ *     80-89    Connection protocol generic
+ *     90-127   Channel related messages
+ *
+ *   Reserved for client protocols:
+ *
+ *     128-191  Reserved
+ *
+ *   Local extensions:
+ *
+ *     192-255  Local extensions
+ */
+/* RCSID("$OpenBSD: ssh2.h,v 1.6 2001/03/27 17:46:49 provos Exp $"); */
+
+/* transport layer: generic */
+
+#define SSH2_MSG_DISCONNECT                            1
+#define SSH2_MSG_IGNORE                                        2
+#define SSH2_MSG_UNIMPLEMENTED                         3
+#define SSH2_MSG_DEBUG                                 4
+#define SSH2_MSG_SERVICE_REQUEST                       5
+#define SSH2_MSG_SERVICE_ACCEPT                                6
+
+/* transport layer: alg negotiation */
+
+#define SSH2_MSG_KEXINIT                               20
+#define SSH2_MSG_NEWKEYS                               21
+
+/* transport layer: kex specific messages, can be reused */
+
+#define SSH2_MSG_KEXDH_INIT                            30
+#define SSH2_MSG_KEXDH_REPLY                           31
+
+/* dh-group-exchange */
+#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD                        30
+#define SSH2_MSG_KEX_DH_GEX_GROUP                      31
+#define SSH2_MSG_KEX_DH_GEX_INIT                       32
+#define SSH2_MSG_KEX_DH_GEX_REPLY                      33
+#define SSH2_MSG_KEX_DH_GEX_REQUEST                    34
+
+/* user authentication: generic */
+
+#define SSH2_MSG_USERAUTH_REQUEST                      50
+#define SSH2_MSG_USERAUTH_FAILURE                      51
+#define SSH2_MSG_USERAUTH_SUCCESS                      52
+#define SSH2_MSG_USERAUTH_BANNER                       53
+
+/* user authentication: method specific, can be reused */
+
+#define SSH2_MSG_USERAUTH_PK_OK                                60
+#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ             60
+#define SSH2_MSG_USERAUTH_INFO_REQUEST                 60
+#define SSH2_MSG_USERAUTH_INFO_RESPONSE                        61
+
+/* connection protocol: generic */
+
+#define SSH2_MSG_GLOBAL_REQUEST                                80
+#define SSH2_MSG_REQUEST_SUCCESS                       81
+#define SSH2_MSG_REQUEST_FAILURE                       82
+
+/* channel related messages */
+
+#define SSH2_MSG_CHANNEL_OPEN                          90
+#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION             91
+#define SSH2_MSG_CHANNEL_OPEN_FAILURE                  92
+#define SSH2_MSG_CHANNEL_WINDOW_ADJUST                 93
+#define SSH2_MSG_CHANNEL_DATA                          94
+#define SSH2_MSG_CHANNEL_EXTENDED_DATA                 95
+#define SSH2_MSG_CHANNEL_EOF                           96
+#define SSH2_MSG_CHANNEL_CLOSE                         97
+#define SSH2_MSG_CHANNEL_REQUEST                       98
+#define SSH2_MSG_CHANNEL_SUCCESS                       99
+#define SSH2_MSG_CHANNEL_FAILURE                       100
+
+/* disconnect reason code */
+
+#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT    1
+#define SSH2_DISCONNECT_PROTOCOL_ERROR                 2
+#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED            3
+#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED     4
+#define SSH2_DISCONNECT_RESERVED                       4
+#define SSH2_DISCONNECT_MAC_ERROR                      5
+#define SSH2_DISCONNECT_COMPRESSION_ERROR              6
+#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE          7
+#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
+#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE                9
+#define SSH2_DISCONNECT_CONNECTION_LOST                        10
+#define SSH2_DISCONNECT_BY_APPLICATION                 11
+#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS           12
+#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER         13
+#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
+#define SSH2_DISCONNECT_ILLEGAL_USER_NAME              15
+
+/* misc */
+
+#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED          1
+#define SSH2_OPEN_CONNECT_FAILED                       2
+#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE                 3
+#define SSH2_OPEN_RESOURCE_SHORTAGE                    4
+
+#define SSH2_EXTENDED_DATA_STDERR                      1
diff --git a/openssh/ssh_config b/openssh/ssh_config
new file mode 100644 (file)
index 0000000..6209354
--- /dev/null
@@ -0,0 +1,35 @@
+#      $OpenBSD: ssh_config,v 1.10 2001/04/03 21:19:38 todd Exp $
+
+# This is ssh client systemwide configuration file.  See ssh(1) for more
+# information.  This file provides defaults for users, and the values can
+# be changed in per-user configuration files or on the command line.
+
+# Configuration data is parsed as follows:
+#  1. command line options
+#  2. user-specific file
+#  3. system-wide file
+# Any configuration value is only changed the first time it is set.
+# Thus, host-specific definitions should be at the beginning of the
+# configuration file, and defaults at the end.
+
+# Site-wide defaults for various options
+
+# Host *
+#   ForwardAgent no
+#   ForwardX11 no
+#   RhostsAuthentication no
+#   RhostsRSAAuthentication yes
+#   RSAAuthentication yes
+#   PasswordAuthentication yes
+#   FallBackToRsh no
+#   UseRsh no
+#   BatchMode no
+#   CheckHostIP yes
+#   StrictHostKeyChecking yes
+#   IdentityFile ~/.ssh/identity
+#   IdentityFile ~/.ssh/id_dsa
+#   IdentityFile ~/.ssh/id_rsa
+#   Port 22
+#   Protocol 2,1
+#   Cipher blowfish
+#   EscapeChar ~
diff --git a/openssh/ssh_prng_cmds.in b/openssh/ssh_prng_cmds.in
new file mode 100644 (file)
index 0000000..003e0e0
--- /dev/null
@@ -0,0 +1,75 @@
+# entropy gathering commands
+
+# Format is: "program-name args" path rate
+
+# The "rate" represents the number of bits of usuable entropy per 
+# byte of command output. Be conservative.
+#
+# $Id$
+
+"ls -alni /var/log"                    @PROG_LS@       0.02
+"ls -alni /var/adm"                    @PROG_LS@       0.02
+"ls -alni /usr/adm"                     @PROG_LS@       0.02
+"ls -alni /var/mail"                   @PROG_LS@       0.02
+"ls -alni /usr/mail"                    @PROG_LS@       0.02
+"ls -alni /var/adm/syslog"             @PROG_LS@       0.02
+"ls -alni /usr/adm/syslog"             @PROG_LS@       0.02
+"ls -alni /var/spool/mail"             @PROG_LS@       0.02
+"ls -alni /proc"                       @PROG_LS@       0.02
+"ls -alni /tmp"                                @PROG_LS@       0.02
+"ls -alni /var/tmp"                    @PROG_LS@       0.02
+"ls -alni /usr/tmp"                    @PROG_LS@       0.02
+"ls -alTi /var/log"                    @PROG_LS@       0.02
+"ls -alTi /var/adm"                    @PROG_LS@       0.02
+"ls -alTi /var/mail"                   @PROG_LS@       0.02
+"ls -alTi /var/adm/syslog"             @PROG_LS@       0.02
+"ls -alTi /var/spool/mail"             @PROG_LS@       0.02
+"ls -alTi /proc"                       @PROG_LS@       0.02
+"ls -alTi /tmp"                                @PROG_LS@       0.02
+"ls -alTi /var/tmp"                    @PROG_LS@       0.02
+"ls -alTi /usr/tmp"                    @PROG_LS@       0.02
+
+"netstat -an"                          @PROG_NETSTAT@  0.05
+"netstat -in"                          @PROG_NETSTAT@  0.05
+"netstat -rn"                          @PROG_NETSTAT@  0.02
+"netstat -pn"                          @PROG_NETSTAT@  0.02
+"netstat -ia"                           @PROG_NETSTAT@  0.05
+"netstat -s"                           @PROG_NETSTAT@  0.02
+"netstat -is"                          @PROG_NETSTAT@  0.07
+
+"arp -a -n"                            @PROG_ARP@      0.02
+
+"ifconfig -a"                          @PROG_IFCONFIG@ 0.02
+
+"ps laxww"                             @PROG_PS@       0.03
+"ps -al"                               @PROG_PS@       0.03
+"ps -efl"                              @PROG_PS@       0.03
+"jstat"                                        @PROG_JSTAT@    0.07
+
+"w"                                    @PROG_W@        0.05
+
+"who -i"                               @PROG_WHO@      0.01
+
+"last"                                 @PROG_LAST@     0.01
+
+"lastlog"                              @PROG_LASTLOG@  0.01
+
+"df"                                   @PROG_DF@       0.01
+"df -i"                                        @PROG_DF@       0.01
+
+"sar -d"                               @PROG_SAR@      0.04
+
+"vmstat"                               @PROG_VMSTAT@   0.01
+"uptime"                               @PROG_UPTIME@   0.01
+
+"ipcs -a"                              @PROG_IPCS@     0.01
+
+"tail -200 /var/log/messages"          @PROG_TAIL@     0.01
+"tail -200 /var/log/syslog"            @PROG_TAIL@     0.01
+"tail -200 /var/adm/messages"          @PROG_TAIL@     0.01
+"tail -200 /var/adm/syslog"            @PROG_TAIL@     0.01
+"tail -200 /var/adm/syslog/syslog.log" @PROG_TAIL@     0.01
+"tail -200 /var/log/maillog"           @PROG_TAIL@     0.01
+"tail -200 /var/adm/maillog"           @PROG_TAIL@     0.01
+"tail -200 /var/adm/syslog/mail.log"   @PROG_TAIL@     0.01
+
diff --git a/openssh/sshconnect.c b/openssh/sshconnect.c
new file mode 100644 (file)
index 0000000..de6cc22
--- /dev/null
@@ -0,0 +1,905 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Code to connect to a remote host, and to perform the client side of the
+ * login (authentication) dialog.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshconnect.c,v 1.115 2001/10/08 19:05:05 markus Exp $");
+
+#include <openssl/bn.h>
+
+#include "ssh.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "packet.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "key.h"
+#include "sshconnect.h"
+#include "hostfile.h"
+#include "log.h"
+#include "readconf.h"
+#include "atomicio.h"
+#include "misc.h"
+
+char *client_version_string = NULL;
+char *server_version_string = NULL;
+
+extern Options options;
+extern char *__progname;
+
+#ifndef INET6_ADDRSTRLEN               /* for non IPv6 machines */
+#define INET6_ADDRSTRLEN 46
+#endif
+
+static const char *
+sockaddr_ntop(struct sockaddr *sa)
+{
+       void *addr;
+       static char addrbuf[INET6_ADDRSTRLEN];
+
+       switch (sa->sa_family) {
+               case AF_INET:
+                       addr = &((struct sockaddr_in *)sa)->sin_addr;
+                       break;
+               case AF_INET6:
+                       addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+                       break;
+               default:
+                       /* This case should be protected against elsewhere */
+                       abort();
+       }
+       inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
+       return addrbuf;
+}
+
+/*
+ * Connect to the given ssh server using a proxy command.
+ */
+static int
+ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
+                 const char *proxy_command)
+{
+       Buffer command;
+       const char *cp;
+       char *command_string;
+       int pin[2], pout[2];
+       pid_t pid;
+       char strport[NI_MAXSERV];
+
+       /* Convert the port number into a string. */
+       snprintf(strport, sizeof strport, "%hu", port);
+
+       /* Build the final command string in the buffer by making the
+          appropriate substitutions to the given proxy command. */
+       buffer_init(&command);
+       for (cp = proxy_command; *cp; cp++) {
+               if (cp[0] == '%' && cp[1] == '%') {
+                       buffer_append(&command, "%", 1);
+                       cp++;
+                       continue;
+               }
+               if (cp[0] == '%' && cp[1] == 'h') {
+                       buffer_append(&command, host, strlen(host));
+                       cp++;
+                       continue;
+               }
+               if (cp[0] == '%' && cp[1] == 'p') {
+                       buffer_append(&command, strport, strlen(strport));
+                       cp++;
+                       continue;
+               }
+               buffer_append(&command, cp, 1);
+       }
+       buffer_append(&command, "\0", 1);
+
+       /* Get the final command string. */
+       command_string = buffer_ptr(&command);
+
+       /* Create pipes for communicating with the proxy. */
+       if (pipe(pin) < 0 || pipe(pout) < 0)
+               fatal("Could not create pipes to communicate with the proxy: %.100s",
+                     strerror(errno));
+
+       debug("Executing proxy command: %.500s", command_string);
+
+       /* Fork and execute the proxy command. */
+       if ((pid = fork()) == 0) {
+               char *argv[10];
+
+               /* Child.  Permanently give up superuser privileges. */
+               permanently_set_uid(pw);
+
+               /* Redirect stdin and stdout. */
+               close(pin[1]);
+               if (pin[0] != 0) {
+                       if (dup2(pin[0], 0) < 0)
+                               perror("dup2 stdin");
+                       close(pin[0]);
+               }
+               close(pout[0]);
+               if (dup2(pout[1], 1) < 0)
+                       perror("dup2 stdout");
+               /* Cannot be 1 because pin allocated two descriptors. */
+               close(pout[1]);
+
+               /* Stderr is left as it is so that error messages get
+                  printed on the user's terminal. */
+               argv[0] = _PATH_BSHELL;
+               argv[1] = "-c";
+               argv[2] = command_string;
+               argv[3] = NULL;
+
+               /* Execute the proxy command.  Note that we gave up any
+                  extra privileges above. */
+               execv(argv[0], argv);
+               perror(argv[0]);
+               exit(1);
+       }
+       /* Parent. */
+       if (pid < 0)
+               fatal("fork failed: %.100s", strerror(errno));
+
+       /* Close child side of the descriptors. */
+       close(pin[0]);
+       close(pout[1]);
+
+       /* Free the command name. */
+       buffer_free(&command);
+
+       /* Set the connection file descriptors. */
+       packet_set_connection(pout[0], pin[1]);
+
+       /* Indicate OK return */
+       return 0;
+}
+
+/*
+ * Creates a (possibly privileged) socket for use as the ssh connection.
+ */
+static int
+ssh_create_socket(struct passwd *pw, int privileged, int family)
+{
+       int sock, gaierr;
+       struct addrinfo hints, *res;
+
+       /*
+        * If we are running as root and want to connect to a privileged
+        * port, bind our own socket to a privileged port.
+        */
+       if (privileged) {
+               int p = IPPORT_RESERVED - 1;
+               sock = rresvport_af(&p, family);
+               if (sock < 0)
+                       error("rresvport: af=%d %.100s", family, strerror(errno));
+               else
+                       debug("Allocated local port %d.", p);
+               return sock;
+       }
+       /*
+        * Just create an ordinary socket on arbitrary port.  We use
+        * the user's uid to create the socket.
+        */
+       temporarily_use_uid(pw);
+       sock = socket(family, SOCK_STREAM, 0);
+       if (sock < 0)
+               error("socket: %.100s", strerror(errno));
+       restore_uid();
+
+       /* Bind the socket to an alternative local IP address */
+       if (options.bind_address == NULL)
+               return sock;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = family;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_PASSIVE;
+       gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
+       if (gaierr) {
+               error("getaddrinfo: %s: %s", options.bind_address,
+                   gai_strerror(gaierr));
+               close(sock);
+               return -1;
+       }
+       if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+               error("bind: %s: %s", options.bind_address, strerror(errno));
+               close(sock);
+               freeaddrinfo(res);
+               return -1;
+       }
+       freeaddrinfo(res);
+       return sock;
+}
+
+/*
+ * Opens a TCP/IP connection to the remote server on the given host.
+ * The address of the remote host will be returned in hostaddr.
+ * If port is 0, the default port will be used.  If anonymous is zero,
+ * a privileged port will be allocated to make the connection.
+ * This requires super-user privileges if anonymous is false.
+ * Connection_attempts specifies the maximum number of tries (one per
+ * second).  If proxy_command is non-NULL, it specifies the command (with %h
+ * and %p substituted for host and port, respectively) to use to contact
+ * the daemon.
+ * Return values:
+ *    0 for OK
+ *    ECONNREFUSED if we got a "Connection Refused" by the peer on any address
+ *    ECONNABORTED if we failed without a "Connection refused"
+ * Suitable error messages for the connection failure will already have been
+ * printed.
+ */
+int
+ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
+    u_short port, int family, int connection_attempts,
+    int anonymous, struct passwd *pw, const char *proxy_command)
+{
+       int gaierr;
+       int on = 1;
+       int sock = -1, attempt;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       struct addrinfo hints, *ai, *aitop;
+       struct linger linger;
+       struct servent *sp;
+       /*
+        * Did we get only other errors than "Connection refused" (which
+        * should block fallback to rsh and similar), or did we get at least
+        * one "Connection refused"?
+        */
+       int full_failure = 1;
+
+       debug("ssh_connect: getuid %u geteuid %u anon %d",
+             (u_int) getuid(), (u_int) geteuid(), anonymous);
+
+       /* Get default port if port has not been set. */
+       if (port == 0) {
+               sp = getservbyname(SSH_SERVICE_NAME, "tcp");
+               if (sp)
+                       port = ntohs(sp->s_port);
+               else
+                       port = SSH_DEFAULT_PORT;
+       }
+       /* If a proxy command is given, connect using it. */
+       if (proxy_command != NULL)
+               return ssh_proxy_connect(host, port, pw, proxy_command);
+
+       /* No proxy command. */
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = family;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", port);
+       if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
+               fatal("%s: %.100s: %s", __progname, host,
+                   gai_strerror(gaierr));
+
+       /*
+        * Try to connect several times.  On some machines, the first time
+        * will sometimes fail.  In general socket code appears to behave
+        * quite magically on many machines.
+                */
+       for (attempt = 0; ;) {
+               if (attempt > 0)
+                       debug("Trying again...");
+
+               /* Loop through addresses for this host, and try each one in
+                  sequence until the connection succeeds. */
+               for (ai = aitop; ai; ai = ai->ai_next) {
+                       if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                               continue;
+                       if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                           ntop, sizeof(ntop), strport, sizeof(strport),
+                           NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                               error("ssh_connect: getnameinfo failed");
+                               continue;
+                       }
+                       debug("Connecting to %.200s [%.100s] port %s.",
+                               host, ntop, strport);
+
+                       /* Create a socket for connecting. */
+                       sock = ssh_create_socket(pw,
+#ifdef HAVE_CYGWIN
+                           !anonymous,
+#else
+                           !anonymous && geteuid() == 0,
+#endif
+                           ai->ai_family);
+                       if (sock < 0)
+                               /* Any error is already output */
+                               continue;
+
+                       /* Connect to the host.  We use the user's uid in the
+                        * hope that it will help with tcp_wrappers showing
+                        * the remote uid as root.
+                        */
+                       temporarily_use_uid(pw);
+                       if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
+                               /* Successful connection. */
+                               memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
+                               restore_uid();
+                               break;
+                       } else {
+                               if (errno == ECONNREFUSED)
+                                       full_failure = 0;
+                               log("ssh: connect to address %s port %s: %s",
+                                   sockaddr_ntop(ai->ai_addr), strport,
+                                   strerror(errno));
+                               restore_uid();
+                               /*
+                                * Close the failed socket; there appear to
+                                * be some problems when reusing a socket for
+                                * which connect() has already returned an
+                                * error.
+                                */
+                               shutdown(sock, SHUT_RDWR);
+                               close(sock);
+                       }
+               }
+               if (ai)
+                       break;  /* Successful connection. */
+
+               attempt++;
+               if (attempt >= connection_attempts)
+                       break;
+               /* Sleep a moment before retrying. */
+               sleep(1);
+       }
+
+       freeaddrinfo(aitop);
+
+       /* Return failure if we didn't get a successful connection. */
+       if (attempt >= connection_attempts)
+               return full_failure ? ECONNABORTED : ECONNREFUSED;
+
+       debug("Connection established.");
+
+       /*
+        * Set socket options.  We would like the socket to disappear as soon
+        * as it has been closed for whatever reason.
+        */
+       /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
+       linger.l_onoff = 1;
+       linger.l_linger = 5;
+       setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
+
+       /* Set keepalives if requested. */
+       if (options.keepalives &&
+           setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
+           sizeof(on)) < 0)
+               error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
+
+       /* Set the connection. */
+       packet_set_connection(sock, sock);
+
+       return 0;
+}
+
+/*
+ * Waits for the server identification string, and sends our own
+ * identification string.
+ */
+static void
+ssh_exchange_identification(void)
+{
+       char buf[256], remote_version[256];     /* must be same size! */
+       int remote_major, remote_minor, i, mismatch;
+       int connection_in = packet_get_connection_in();
+       int connection_out = packet_get_connection_out();
+       int minor1 = PROTOCOL_MINOR_1;
+
+       /* Read other side\'s version identification. */
+       for (;;) {
+               for (i = 0; i < sizeof(buf) - 1; i++) {
+                       int len = atomicio(read, connection_in, &buf[i], 1);
+                       if (len < 0)
+                               fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
+                       if (len != 1)
+                               fatal("ssh_exchange_identification: Connection closed by remote host");
+                       if (buf[i] == '\r') {
+                               buf[i] = '\n';
+                               buf[i + 1] = 0;
+                               continue;               /**XXX wait for \n */
+                       }
+                       if (buf[i] == '\n') {
+                               buf[i + 1] = 0;
+                               break;
+                       }
+               }
+               buf[sizeof(buf) - 1] = 0;
+               if (strncmp(buf, "SSH-", 4) == 0)
+                       break;
+               debug("ssh_exchange_identification: %s", buf);
+       }
+       server_version_string = xstrdup(buf);
+
+       /*
+        * Check that the versions match.  In future this might accept
+        * several versions and set appropriate flags to handle them.
+        */
+       if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
+           &remote_major, &remote_minor, remote_version) != 3)
+               fatal("Bad remote protocol version identification: '%.100s'", buf);
+       debug("Remote protocol version %d.%d, remote software version %.100s",
+             remote_major, remote_minor, remote_version);
+
+       compat_datafellows(remote_version);
+       mismatch = 0;
+
+       switch(remote_major) {
+       case 1:
+               if (remote_minor == 99 &&
+                   (options.protocol & SSH_PROTO_2) &&
+                   !(options.protocol & SSH_PROTO_1_PREFERRED)) {
+                       enable_compat20();
+                       break;
+               }
+               if (!(options.protocol & SSH_PROTO_1)) {
+                       mismatch = 1;
+                       break;
+               }
+               if (remote_minor < 3) {
+                       fatal("Remote machine has too old SSH software version.");
+               } else if (remote_minor == 3 || remote_minor == 4) {
+                       /* We speak 1.3, too. */
+                       enable_compat13();
+                       minor1 = 3;
+                       if (options.forward_agent) {
+                               log("Agent forwarding disabled for protocol 1.3");
+                               options.forward_agent = 0;
+                       }
+               }
+               break;
+       case 2:
+               if (options.protocol & SSH_PROTO_2) {
+                       enable_compat20();
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               mismatch = 1;
+               break;
+       }
+       if (mismatch)
+               fatal("Protocol major versions differ: %d vs. %d",
+                   (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+                   remote_major);
+       /* Send our own protocol version identification. */
+       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
+           compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+           compat20 ? PROTOCOL_MINOR_2 : minor1,
+           SSH_VERSION);
+       if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
+               fatal("write: %.100s", strerror(errno));
+       client_version_string = xstrdup(buf);
+       chop(client_version_string);
+       chop(server_version_string);
+       debug("Local version string %.100s", client_version_string);
+}
+
+/* defaults to 'no' */
+static int
+confirm(const char *prompt)
+{
+       char buf[1024];
+       FILE *f;
+       int retval = -1;
+
+       if (options.batch_mode)
+               return 0;
+       if (isatty(STDIN_FILENO))
+               f = stdin;
+       else
+               f = fopen(_PATH_TTY, "rw");
+       if (f == NULL)
+               return 0;
+       fflush(stdout);
+       fprintf(stderr, "%s", prompt);
+       while (1) {
+               if (fgets(buf, sizeof(buf), f) == NULL) {
+                       fprintf(stderr, "\n");
+                       strlcpy(buf, "no", sizeof buf);
+               }
+               /* Remove newline from response. */
+               if (strchr(buf, '\n'))
+                       *strchr(buf, '\n') = 0;
+               if (strcmp(buf, "yes") == 0)
+                       retval = 1;
+               else if (strcmp(buf, "no") == 0)
+                       retval = 0;
+               else
+                       fprintf(stderr, "Please type 'yes' or 'no': ");
+
+               if (retval != -1) {
+                       if (f != stdin)
+                               fclose(f);
+                       return retval;
+               }
+       }
+}
+
+/*
+ * check whether the supplied host key is valid, return -1 if the key
+ * is not valid. the user_hostfile will not be updated if 'readonly' is true.
+ */
+
+static int
+check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
+    int readonly, const char *user_hostfile, const char *system_hostfile)
+{
+       Key *file_key;
+       char *type = key_type(host_key);
+       char *ip = NULL;
+       char hostline[1000], *hostp, *fp;
+       HostStatus host_status;
+       HostStatus ip_status;
+       int local = 0, host_ip_differ = 0;
+       int salen;
+       char ntop[NI_MAXHOST];
+       int host_line, ip_line;
+       const char *host_file = NULL, *ip_file = NULL;
+
+       /*
+        * Force accepting of the host key for loopback/localhost. The
+        * problem is that if the home directory is NFS-mounted to multiple
+        * machines, localhost will refer to a different machine in each of
+        * them, and the user will get bogus HOST_CHANGED warnings.  This
+        * essentially disables host authentication for localhost; however,
+        * this is probably not a real problem.
+        */
+       /**  hostaddr == 0! */
+       switch (hostaddr->sa_family) {
+       case AF_INET:
+               local = (ntohl(((struct sockaddr_in *)hostaddr)->
+                   sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
+               salen = sizeof(struct sockaddr_in);
+               break;
+       case AF_INET6:
+               local = IN6_IS_ADDR_LOOPBACK(
+                   &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
+               salen = sizeof(struct sockaddr_in6);
+               break;
+       default:
+               local = 0;
+               salen = sizeof(struct sockaddr_storage);
+               break;
+       }
+       if (options.no_host_authentication_for_localhost == 1 && local &&
+           options.host_key_alias == NULL) {
+               debug("Forcing accepting of host key for "
+                   "loopback/localhost.");
+               return 0;
+       }
+
+       /*
+        * We don't have the remote ip-address for connections
+        * using a proxy command
+        */
+       if (options.proxy_command == NULL) {
+               if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
+                   NULL, 0, NI_NUMERICHOST) != 0)
+                       fatal("check_host_key: getnameinfo failed");
+               ip = xstrdup(ntop);
+       } else {
+               ip = xstrdup("<no hostip for proxy command>");
+       }
+       /*
+        * Turn off check_host_ip if the connection is to localhost, via proxy
+        * command or if we don't have a hostname to compare with
+        */
+       if (options.check_host_ip &&
+           (local || strcmp(host, ip) == 0 || options.proxy_command != NULL))
+               options.check_host_ip = 0;
+
+       /*
+        * Allow the user to record the key under a different name. This is
+        * useful for ssh tunneling over forwarded connections or if you run
+        * multiple sshd's on different ports on the same machine.
+        */
+       if (options.host_key_alias != NULL) {
+               host = options.host_key_alias;
+               debug("using hostkeyalias: %s", host);
+       }
+
+       /*
+        * Store the host key from the known host file in here so that we can
+        * compare it with the key for the IP address.
+        */
+       file_key = key_new(host_key->type);
+
+       /*
+        * Check if the host key is present in the user\'s list of known
+        * hosts or in the systemwide list.
+        */
+       host_file = user_hostfile;
+       host_status = check_host_in_hostfile(host_file, host, host_key,
+            file_key, &host_line);
+       if (host_status == HOST_NEW) {
+               host_file = system_hostfile;
+               host_status = check_host_in_hostfile(host_file, host, host_key,
+                   file_key, &host_line);
+       }
+       /*
+        * Also perform check for the ip address, skip the check if we are
+        * localhost or the hostname was an ip address to begin with
+        */
+       if (options.check_host_ip) {
+               Key *ip_key = key_new(host_key->type);
+
+               ip_file = user_hostfile;
+               ip_status = check_host_in_hostfile(ip_file, ip, host_key,
+                   ip_key, &ip_line);
+               if (ip_status == HOST_NEW) {
+                       ip_file = system_hostfile;
+                       ip_status = check_host_in_hostfile(ip_file, ip,
+                           host_key, ip_key, &ip_line);
+               }
+               if (host_status == HOST_CHANGED &&
+                   (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
+                       host_ip_differ = 1;
+
+               key_free(ip_key);
+       } else
+               ip_status = host_status;
+
+       key_free(file_key);
+
+       switch (host_status) {
+       case HOST_OK:
+               /* The host is known and the key matches. */
+               debug("Host '%.200s' is known and matches the %s host key.",
+                   host, type);
+               debug("Found key in %s:%d", host_file, host_line);
+               if (options.check_host_ip && ip_status == HOST_NEW) {
+                       if (readonly)
+                               log("%s host key for IP address "
+                                   "'%.128s' not in list of known hosts.",
+                                   type, ip);
+                       else if (!add_host_to_hostfile(user_hostfile, ip,
+                            host_key))
+                               log("Failed to add the %s host key for IP "
+                                   "address '%.128s' to the list of known "
+                                   "hosts (%.30s).", type, ip, user_hostfile);
+                       else
+                               log("Warning: Permanently added the %s host "
+                                   "key for IP address '%.128s' to the list "
+                                   "of known hosts.", type, ip);
+               }
+               break;
+       case HOST_NEW:
+               if (readonly)
+                       goto fail;
+               /* The host is new. */
+               if (options.strict_host_key_checking == 1) {
+                       /*
+                        * User has requested strict host key checking.  We
+                        * will not add the host key automatically.  The only
+                        * alternative left is to abort.
+                        */
+                       error("No %s host key is known for %.200s and you "
+                           "have requested strict checking.", type, host);
+                       goto fail;
+               } else if (options.strict_host_key_checking == 2) {
+                       /* The default */
+                       char prompt[1024];
+                       fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+                       snprintf(prompt, sizeof(prompt),
+                           "The authenticity of host '%.200s (%s)' can't be "
+                           "established.\n"
+                           "%s key fingerprint is %s.\n"
+                           "Are you sure you want to continue connecting "
+                           "(yes/no)? ", host, ip, type, fp);
+                       xfree(fp);
+                       if (!confirm(prompt)) {
+                               goto fail;
+                       }
+               }
+               if (options.check_host_ip && ip_status == HOST_NEW) {
+                       snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
+                       hostp = hostline;
+               } else
+                       hostp = host;
+
+               /*
+                * If not in strict mode, add the key automatically to the
+                * local known_hosts file.
+                */
+               if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
+                       log("Failed to add the host to the list of known "
+                           "hosts (%.500s).", user_hostfile);
+               else
+                       log("Warning: Permanently added '%.200s' (%s) to the "
+                           "list of known hosts.", hostp, type);
+               break;
+       case HOST_CHANGED:
+               if (options.check_host_ip && host_ip_differ) {
+                       char *msg;
+                       if (ip_status == HOST_NEW)
+                               msg = "is unknown";
+                       else if (ip_status == HOST_OK)
+                               msg = "is unchanged";
+                       else
+                               msg = "has a different value";
+                       error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+                       error("@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @");
+                       error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+                       error("The %s host key for %s has changed,", type, host);
+                       error("and the key for the according IP address %s", ip);
+                       error("%s. This could either mean that", msg);
+                       error("DNS SPOOFING is happening or the IP address for the host");
+                       error("and its host key have changed at the same time.");
+                       if (ip_status != HOST_NEW)
+                               error("Offending key for IP in %s:%d", ip_file, ip_line);
+               }
+               /* The host key has changed. */
+               fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
+               error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
+               error("It is also possible that the %s host key has just been changed.", type);
+               error("The fingerprint for the %s key sent by the remote host is\n%s.",
+                   type, fp);
+               error("Please contact your system administrator.");
+               error("Add correct host key in %.100s to get rid of this message.",
+                   user_hostfile);
+               error("Offending key in %s:%d", host_file, host_line);
+               xfree(fp);
+
+               /*
+                * If strict host key checking is in use, the user will have
+                * to edit the key manually and we can only abort.
+                */
+               if (options.strict_host_key_checking) {
+                       error("%s host key for %.200s has changed and you have "
+                           "requested strict checking.", type, host);
+                       goto fail;
+               }
+
+               /*
+                * If strict host key checking has not been requested, allow
+                * the connection but without password authentication or
+                * agent forwarding.
+                */
+               if (options.password_authentication) {
+                       error("Password authentication is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.password_authentication = 0;
+               }
+               if (options.forward_agent) {
+                       error("Agent forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.forward_agent = 0;
+               }
+               if (options.forward_x11) {
+                       error("X11 forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.forward_x11 = 0;
+               }
+               if (options.num_local_forwards > 0 ||
+                   options.num_remote_forwards > 0) {
+                       error("Port forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.num_local_forwards =
+                            options.num_remote_forwards = 0;
+               }
+               /*
+                * XXX Should permit the user to change to use the new id.
+                * This could be done by converting the host key to an
+                * identifying sentence, tell that the host identifies itself
+                * by that sentence, and ask the user if he/she whishes to
+                * accept the authentication.
+                */
+               break;
+       }
+
+       if (options.check_host_ip && host_status != HOST_CHANGED &&
+           ip_status == HOST_CHANGED) {
+               log("Warning: the %s host key for '%.200s' "
+                   "differs from the key for the IP address '%.128s'",
+                   type, host, ip);
+               if (host_status == HOST_OK)
+                       log("Matching host key in %s:%d", host_file, host_line);
+               log("Offending key for IP in %s:%d", ip_file, ip_line);
+               if (options.strict_host_key_checking == 1) {
+                       error("Exiting, you have requested strict checking.");
+                       goto fail;
+               } else if (options.strict_host_key_checking == 2) {
+                       if (!confirm("Are you sure you want " 
+                           "to continue connecting (yes/no)? ")) {
+                               goto fail;
+                       }
+               }
+       }
+
+       xfree(ip);
+       return 0;
+
+fail:
+       xfree(ip);
+       return -1;
+}
+
+int
+verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
+{
+       struct stat st;
+
+       /* return ok if the key can be found in an old keyfile */
+       if (stat(options.system_hostfile2, &st) == 0 ||
+           stat(options.user_hostfile2, &st) == 0) {
+               if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1,
+                   options.user_hostfile2, options.system_hostfile2) == 0)
+                       return 0;
+       }
+       return check_host_key(host, hostaddr, host_key, /*readonly*/ 0,
+           options.user_hostfile, options.system_hostfile);
+}
+
+/*
+ * Starts a dialog with the server, and authenticates the current user on the
+ * server.  This does not need any extra privileges.  The basic connection
+ * to the server must already have been established before this is called.
+ * If login fails, this function prints an error and never returns.
+ * This function does not require super-user privileges.
+ */
+void
+ssh_login(Key **keys, int nkeys, const char *orighost,
+    struct sockaddr *hostaddr, struct passwd *pw)
+{
+       char *host, *cp;
+       char *server_user, *local_user;
+
+       local_user = xstrdup(pw->pw_name);
+       server_user = options.user ? options.user : local_user;
+
+       /* Convert the user-supplied hostname into all lowercase. */
+       host = xstrdup(orighost);
+       for (cp = host; *cp; cp++)
+               if (isupper(*cp))
+                       *cp = tolower(*cp);
+
+       /* Exchange protocol version identification strings with the server. */
+       ssh_exchange_identification();
+
+       /* Put the connection into non-blocking mode. */
+       packet_set_nonblocking();
+
+       /* key exchange */
+       /* authenticate user */
+       if (compat20) {
+               ssh_kex2(host, hostaddr);
+               ssh_userauth2(local_user, server_user, host, keys, nkeys);
+       } else {
+               ssh_kex(host, hostaddr);
+               ssh_userauth1(local_user, server_user, host, keys, nkeys);
+       }
+}
+
+void
+ssh_put_password(char *password)
+{
+       int size;
+       char *padded;
+
+       if (datafellows & SSH_BUG_PASSWORDPAD) {
+               packet_put_cstring(password);
+               return;
+       }
+       size = roundup(strlen(password) + 1, 32);
+       padded = xmalloc(size);
+       memset(padded, 0, size);
+       strlcpy(padded, password, size);
+       packet_put_string(padded, size);
+       memset(padded, 0, size);
+       xfree(padded);
+}
diff --git a/openssh/sshconnect.h b/openssh/sshconnect.h
new file mode 100644 (file)
index 0000000..b475add
--- /dev/null
@@ -0,0 +1,46 @@
+/*     $OpenBSD: sshconnect.h,v 1.13 2001/10/08 19:05:05 markus Exp $  */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SSHCONNECT_H
+#define SSHCONNECT_H
+
+int
+ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
+    int, struct passwd *, const char *);
+
+void
+ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *);
+
+int     verify_host_key(char *, struct sockaddr *, Key *);
+
+void    ssh_kex(char *, struct sockaddr *);
+void    ssh_kex2(char *, struct sockaddr *);
+
+void    ssh_userauth1(const char *, const char *, char *, Key **, int);
+void    ssh_userauth2(const char *, const char *, char *, Key **, int);
+
+void    ssh_put_password(char *);
+
+#endif
diff --git a/openssh/sshconnect1.c b/openssh/sshconnect1.c
new file mode 100644 (file)
index 0000000..d6b8623
--- /dev/null
@@ -0,0 +1,1276 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Code to connect to a remote host, and to perform the client side of the
+ * login (authentication) dialog.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshconnect1.c,v 1.41 2001/10/06 11:18:19 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+#ifdef KRB4
+#include <krb.h>
+#endif
+#ifdef KRB5
+#include <krb5.h>
+#endif
+#ifdef AFS
+#include <kafs.h>
+#include "radix.h"
+#endif
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "packet.h"
+#include "mpaux.h"
+#include "uidswap.h"
+#include "log.h"
+#include "readconf.h"
+#include "key.h"
+#include "authfd.h"
+#include "sshconnect.h"
+#include "authfile.h"
+#include "readpass.h"
+#include "cipher.h"
+#include "canohost.h"
+#include "auth.h"
+
+/* Session id for the current session. */
+u_char session_id[16];
+u_int supported_authentications = 0;
+
+extern Options options;
+extern char *__progname;
+
+/*
+ * Checks if the user has an authentication agent, and if so, tries to
+ * authenticate using the agent.
+ */
+static int
+try_agent_authentication(void)
+{
+       int type;
+       char *comment;
+       AuthenticationConnection *auth;
+       u_char response[16];
+       u_int i;
+       int plen, clen;
+       Key *key;
+       BIGNUM *challenge;
+
+       /* Get connection to the agent. */
+       auth = ssh_get_authentication_connection();
+       if (!auth)
+               return 0;
+
+       challenge = BN_new();
+
+       /* Loop through identities served by the agent. */
+       for (key = ssh_get_first_identity(auth, &comment, 1);
+            key != NULL;
+            key = ssh_get_next_identity(auth, &comment, 1)) {
+
+               /* Try this identity. */
+               debug("Trying RSA authentication via agent with '%.100s'", comment);
+               xfree(comment);
+
+               /* Tell the server that we are willing to authenticate using this key. */
+               packet_start(SSH_CMSG_AUTH_RSA);
+               packet_put_bignum(key->rsa->n);
+               packet_send();
+               packet_write_wait();
+
+               /* Wait for server's response. */
+               type = packet_read(&plen);
+
+               /* The server sends failure if it doesn\'t like our key or
+                  does not support RSA authentication. */
+               if (type == SSH_SMSG_FAILURE) {
+                       debug("Server refused our key.");
+                       key_free(key);
+                       continue;
+               }
+               /* Otherwise it should have sent a challenge. */
+               if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+                       packet_disconnect("Protocol error during RSA authentication: %d",
+                                         type);
+
+               packet_get_bignum(challenge, &clen);
+
+               packet_integrity_check(plen, clen, type);
+
+               debug("Received RSA challenge from server.");
+
+               /* Ask the agent to decrypt the challenge. */
+               if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) {
+                       /*
+                        * The agent failed to authenticate this identifier
+                        * although it advertised it supports this.  Just
+                        * return a wrong value.
+                        */
+                       log("Authentication agent failed to decrypt challenge.");
+                       memset(response, 0, sizeof(response));
+               }
+               key_free(key);
+               debug("Sending response to RSA challenge.");
+
+               /* Send the decrypted challenge back to the server. */
+               packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+               for (i = 0; i < 16; i++)
+                       packet_put_char(response[i]);
+               packet_send();
+               packet_write_wait();
+
+               /* Wait for response from the server. */
+               type = packet_read(&plen);
+
+               /* The server returns success if it accepted the authentication. */
+               if (type == SSH_SMSG_SUCCESS) {
+                       ssh_close_authentication_connection(auth);
+                       BN_clear_free(challenge);
+                       debug("RSA authentication accepted by server.");
+                       return 1;
+               }
+               /* Otherwise it should return failure. */
+               if (type != SSH_SMSG_FAILURE)
+                       packet_disconnect("Protocol error waiting RSA auth response: %d",
+                                         type);
+       }
+       ssh_close_authentication_connection(auth);
+       BN_clear_free(challenge);
+       debug("RSA authentication using agent refused.");
+       return 0;
+}
+
+/*
+ * Computes the proper response to a RSA challenge, and sends the response to
+ * the server.
+ */
+static void
+respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
+{
+       u_char buf[32], response[16];
+       MD5_CTX md;
+       int i, len;
+
+       /* Decrypt the challenge using the private key. */
+       /* XXX think about Bleichenbacher, too */
+       if (rsa_private_decrypt(challenge, challenge, prv) <= 0)
+               packet_disconnect(
+                   "respond_to_rsa_challenge: rsa_private_decrypt failed");
+
+       /* Compute the response. */
+       /* The response is MD5 of decrypted challenge plus session id. */
+       len = BN_num_bytes(challenge);
+       if (len <= 0 || len > sizeof(buf))
+               packet_disconnect(
+                   "respond_to_rsa_challenge: bad challenge length %d", len);
+
+       memset(buf, 0, sizeof(buf));
+       BN_bn2bin(challenge, buf + sizeof(buf) - len);
+       MD5_Init(&md);
+       MD5_Update(&md, buf, 32);
+       MD5_Update(&md, session_id, 16);
+       MD5_Final(response, &md);
+
+       debug("Sending response to host key RSA challenge.");
+
+       /* Send the response back to the server. */
+       packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+       for (i = 0; i < 16; i++)
+               packet_put_char(response[i]);
+       packet_send();
+       packet_write_wait();
+
+       memset(buf, 0, sizeof(buf));
+       memset(response, 0, sizeof(response));
+       memset(&md, 0, sizeof(md));
+}
+
+/*
+ * Checks if the user has authentication file, and if so, tries to authenticate
+ * the user using it.
+ */
+static int
+try_rsa_authentication(int idx)
+{
+       BIGNUM *challenge;
+       Key *public, *private;
+       char buf[300], *passphrase, *comment, *authfile;
+       int i, type, quit, plen, clen;
+
+       public = options.identity_keys[idx];
+       authfile = options.identity_files[idx];
+       comment = xstrdup(authfile);
+
+       debug("Trying RSA authentication with key '%.100s'", comment);
+
+       /* Tell the server that we are willing to authenticate using this key. */
+       packet_start(SSH_CMSG_AUTH_RSA);
+       packet_put_bignum(public->rsa->n);
+       packet_send();
+       packet_write_wait();
+
+       /* Wait for server's response. */
+       type = packet_read(&plen);
+
+       /*
+        * The server responds with failure if it doesn\'t like our key or
+        * doesn\'t support RSA authentication.
+        */
+       if (type == SSH_SMSG_FAILURE) {
+               debug("Server refused our key.");
+               xfree(comment);
+               return 0;
+       }
+       /* Otherwise, the server should respond with a challenge. */
+       if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+               packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+       /* Get the challenge from the packet. */
+       challenge = BN_new();
+       packet_get_bignum(challenge, &clen);
+
+       packet_integrity_check(plen, clen, type);
+
+       debug("Received RSA challenge from server.");
+
+       /*
+        * If the key is not stored in external hardware, we have to
+        * load the private key.  Try first with empty passphrase; if it
+        * fails, ask for a passphrase.
+        */
+       if (public->flags && KEY_FLAG_EXT)
+               private = public;
+       else
+               private = key_load_private_type(KEY_RSA1, authfile, "", NULL);
+       if (private == NULL && !options.batch_mode) {
+               snprintf(buf, sizeof(buf),
+                   "Enter passphrase for RSA key '%.100s': ", comment);
+               for (i = 0; i < options.number_of_password_prompts; i++) {
+                       passphrase = read_passphrase(buf, 0);
+                       if (strcmp(passphrase, "") != 0) {
+                               private = key_load_private_type(KEY_RSA1,
+                                   authfile, passphrase, NULL);
+                               quit = 0;
+                       } else {
+                               debug2("no passphrase given, try next key");
+                               quit = 1;
+                       }
+                       memset(passphrase, 0, strlen(passphrase));
+                       xfree(passphrase);
+                       if (private != NULL || quit)
+                               break;
+                       debug2("bad passphrase given, try again...");
+               }
+       }
+       /* We no longer need the comment. */
+       xfree(comment);
+
+       if (private == NULL) {
+               if (!options.batch_mode)
+                       error("Bad passphrase.");
+
+               /* Send a dummy response packet to avoid protocol error. */
+               packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+               for (i = 0; i < 16; i++)
+                       packet_put_char(0);
+               packet_send();
+               packet_write_wait();
+
+               /* Expect the server to reject it... */
+               packet_read_expect(&plen, SSH_SMSG_FAILURE);
+               BN_clear_free(challenge);
+               return 0;
+       }
+
+       /* Compute and send a response to the challenge. */
+       respond_to_rsa_challenge(challenge, private->rsa);
+
+       /* Destroy the private key unless it in external hardware. */
+       if (!(private->flags & KEY_FLAG_EXT))
+               key_free(private);
+
+       /* We no longer need the challenge. */
+       BN_clear_free(challenge);
+
+       /* Wait for response from the server. */
+       type = packet_read(&plen);
+       if (type == SSH_SMSG_SUCCESS) {
+               debug("RSA authentication accepted by server.");
+               return 1;
+       }
+       if (type != SSH_SMSG_FAILURE)
+               packet_disconnect("Protocol error waiting RSA auth response: %d", type);
+       debug("RSA authentication refused.");
+       return 0;
+}
+
+/*
+ * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
+ * authentication and RSA host authentication.
+ */
+static int
+try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
+{
+       int type;
+       BIGNUM *challenge;
+       int plen, clen;
+
+       debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
+
+       /* Tell the server that we are willing to authenticate using this key. */
+       packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
+       packet_put_cstring(local_user);
+       packet_put_int(BN_num_bits(host_key->rsa->n));
+       packet_put_bignum(host_key->rsa->e);
+       packet_put_bignum(host_key->rsa->n);
+       packet_send();
+       packet_write_wait();
+
+       /* Wait for server's response. */
+       type = packet_read(&plen);
+
+       /* The server responds with failure if it doesn't admit our
+          .rhosts authentication or doesn't know our host key. */
+       if (type == SSH_SMSG_FAILURE) {
+               debug("Server refused our rhosts authentication or host key.");
+               return 0;
+       }
+       /* Otherwise, the server should respond with a challenge. */
+       if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+               packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+       /* Get the challenge from the packet. */
+       challenge = BN_new();
+       packet_get_bignum(challenge, &clen);
+
+       packet_integrity_check(plen, clen, type);
+
+       debug("Received RSA challenge for host key from server.");
+
+       /* Compute a response to the challenge. */
+       respond_to_rsa_challenge(challenge, host_key->rsa);
+
+       /* We no longer need the challenge. */
+       BN_clear_free(challenge);
+
+       /* Wait for response from the server. */
+       type = packet_read(&plen);
+       if (type == SSH_SMSG_SUCCESS) {
+               debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
+               return 1;
+       }
+       if (type != SSH_SMSG_FAILURE)
+               packet_disconnect("Protocol error waiting RSA auth response: %d", type);
+       debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
+       return 0;
+}
+
+#ifdef KRB4
+static int
+try_krb4_authentication(void)
+{
+       KTEXT_ST auth;          /* Kerberos data */
+       char *reply;
+       char inst[INST_SZ];
+       char *realm;
+       CREDENTIALS cred;
+       int r, type, plen;
+       socklen_t slen;
+       Key_schedule schedule;
+       u_long checksum, cksum;
+       MSG_DAT msg_data;
+       struct sockaddr_in local, foreign;
+       struct stat st;
+
+       /* Don't do anything if we don't have any tickets. */
+       if (stat(tkt_string(), &st) < 0)
+               return 0;
+       
+       strlcpy(inst, (char *)krb_get_phost(get_canonical_hostname(1)),
+           INST_SZ);
+       
+       realm = (char *)krb_realmofhost(get_canonical_hostname(1));
+       if (!realm) {
+               debug("Kerberos v4: no realm for %s", get_canonical_hostname(1));
+               return 0;
+       }
+       /* This can really be anything. */
+       checksum = (u_long)getpid();
+       
+       r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
+       if (r != KSUCCESS) {
+               debug("Kerberos v4 krb_mk_req failed: %s", krb_err_txt[r]);
+               return 0;
+       }
+       /* Get session key to decrypt the server's reply with. */
+       r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
+       if (r != KSUCCESS) {
+               debug("get_cred failed: %s", krb_err_txt[r]);
+               return 0;
+       }
+       des_key_sched((des_cblock *) cred.session, schedule);
+       
+       /* Send authentication info to server. */
+       packet_start(SSH_CMSG_AUTH_KERBEROS);
+       packet_put_string((char *) auth.dat, auth.length);
+       packet_send();
+       packet_write_wait();
+       
+       /* Zero the buffer. */
+       (void) memset(auth.dat, 0, MAX_KTXT_LEN);
+       
+       slen = sizeof(local);
+       memset(&local, 0, sizeof(local));
+       if (getsockname(packet_get_connection_in(),
+           (struct sockaddr *)&local, &slen) < 0)
+               debug("getsockname failed: %s", strerror(errno));
+       
+       slen = sizeof(foreign);
+       memset(&foreign, 0, sizeof(foreign));
+       if (getpeername(packet_get_connection_in(),
+           (struct sockaddr *)&foreign, &slen) < 0) {
+               debug("getpeername failed: %s", strerror(errno));
+               fatal_cleanup();
+       }
+       /* Get server reply. */
+       type = packet_read(&plen);
+       switch (type) {
+       case SSH_SMSG_FAILURE:
+               /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
+               debug("Kerberos v4 authentication failed.");
+               return 0;
+               break;
+               
+       case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
+               /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
+               debug("Kerberos v4 authentication accepted.");
+               
+               /* Get server's response. */
+               reply = packet_get_string((u_int *) &auth.length);
+               memcpy(auth.dat, reply, auth.length);
+               xfree(reply);
+               
+               packet_integrity_check(plen, 4 + auth.length, type);
+               
+               /*
+                * If his response isn't properly encrypted with the session
+                * key, and the decrypted checksum fails to match, he's
+                * bogus. Bail out.
+                */
+               r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
+                   &foreign, &local, &msg_data);
+               if (r != KSUCCESS) {
+                       debug("Kerberos v4 krb_rd_priv failed: %s",
+                           krb_err_txt[r]);
+                       packet_disconnect("Kerberos v4 challenge failed!");
+               }
+               /* Fetch the (incremented) checksum that we supplied in the request. */
+               memcpy((char *)&cksum, (char *)msg_data.app_data,
+                   sizeof(cksum));
+               cksum = ntohl(cksum);
+               
+               /* If it matches, we're golden. */
+               if (cksum == checksum + 1) {
+                       debug("Kerberos v4 challenge successful.");
+                       return 1;
+               } else
+                       packet_disconnect("Kerberos v4 challenge failed!");
+               break;
+               
+       default:
+               packet_disconnect("Protocol error on Kerberos v4 response: %d", type);
+       }
+       return 0;
+}
+
+#endif /* KRB4 */
+
+#ifdef KRB5
+static int
+try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context)
+{
+       krb5_error_code problem;
+       const char *tkfile;
+       struct stat buf;
+       krb5_ccache ccache = NULL;
+       const char *remotehost;
+       krb5_data ap;
+       int type, payload_len;
+       krb5_ap_rep_enc_part *reply = NULL;
+       int ret;
+       
+       memset(&ap, 0, sizeof(ap));
+       
+       problem = krb5_init_context(context);
+       if (problem) {
+               debug("Kerberos v5: krb5_init_context failed");
+               ret = 0;
+               goto out;
+       }
+       
+       tkfile = krb5_cc_default_name(*context);
+       if (strncmp(tkfile, "FILE:", 5) == 0)
+               tkfile += 5;
+       
+       if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
+               debug("Kerberos v5: could not get default ccache (permission denied).");
+               ret = 0;
+               goto out;
+       }
+       
+       problem = krb5_cc_default(*context, &ccache);
+       if (problem) {
+               debug("Kerberos v5: krb5_cc_default failed: %s",
+                   krb5_get_err_text(*context, problem));
+               ret = 0;
+               goto out;
+       }
+       
+       remotehost = get_canonical_hostname(1);
+       
+       problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED,
+           "host", remotehost, NULL, ccache, &ap);
+       if (problem) {
+               debug("Kerberos v5: krb5_mk_req failed: %s",
+                   krb5_get_err_text(*context, problem));
+               ret = 0;
+               goto out;
+       }
+       
+       packet_start(SSH_CMSG_AUTH_KERBEROS);
+       packet_put_string((char *) ap.data, ap.length);
+       packet_send();
+       packet_write_wait();
+       
+       xfree(ap.data);
+       ap.length = 0;
+       
+       type = packet_read(&payload_len);
+       switch (type) {
+        case SSH_SMSG_FAILURE:
+                /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
+                debug("Kerberos v5 authentication failed.");
+                ret = 0;
+                break;
+               
+       case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
+                /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
+                debug("Kerberos v5 authentication accepted.");
+               
+                /* Get server's response. */
+                ap.data = packet_get_string((unsigned int *) &ap.length);
+               
+                packet_integrity_check(payload_len, 4 + ap.length, type);
+                /* XXX je to dobre? */
+               
+                problem = krb5_rd_rep(*context, *auth_context, &ap, &reply);
+                if (problem) {
+                       ret = 0;
+               }
+               ret = 1;
+               break;
+               
+       default:
+               packet_disconnect("Protocol error on Kerberos v5 response: %d",
+                   type);
+               ret = 0;
+               break;
+               
+       }
+       
+ out:
+       if (ccache != NULL)
+               krb5_cc_close(*context, ccache);
+       if (reply != NULL)
+               krb5_free_ap_rep_enc_part(*context, reply);
+       if (ap.length > 0)
+               krb5_data_free(&ap);
+       
+       return (ret);
+}
+
+static void
+send_krb5_tgt(krb5_context context, krb5_auth_context auth_context)
+{
+       int fd, type, payload_len;
+       krb5_error_code problem;
+       krb5_data outbuf;
+       krb5_ccache ccache = NULL;
+       krb5_creds creds;
+       krb5_kdc_flags flags;
+       const char *remotehost;
+       
+       memset(&creds, 0, sizeof(creds));
+       memset(&outbuf, 0, sizeof(outbuf));
+       
+       fd = packet_get_connection_in();
+       
+       problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd);
+       if (problem)
+               goto out;
+       
+       problem = krb5_cc_default(context, &ccache);
+       if (problem)
+               goto out;
+       
+       problem = krb5_cc_get_principal(context, ccache, &creds.client);
+       if (problem)
+               goto out;
+       
+       problem = krb5_build_principal(context, &creds.server,
+           strlen(creds.client->realm), creds.client->realm,
+           "krbtgt", creds.client->realm, NULL);
+       if (problem)
+               goto out;
+       
+       creds.times.endtime = 0;
+       
+       flags.i = 0;
+       flags.b.forwarded = 1;
+       flags.b.forwardable = krb5_config_get_bool(context,  NULL,
+           "libdefaults", "forwardable", NULL);
+       
+       remotehost = get_canonical_hostname(1);
+       
+       problem = krb5_get_forwarded_creds(context, auth_context,
+           ccache, flags.i, remotehost, &creds, &outbuf);
+       if (problem)
+               goto out;
+       
+       packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
+       packet_put_string((char *)outbuf.data, outbuf.length);
+       packet_send();
+       packet_write_wait();
+       
+       type = packet_read(&payload_len);
+       
+       if (type == SSH_SMSG_SUCCESS) {
+               char *pname;
+               
+               krb5_unparse_name(context, creds.client, &pname);
+               debug("Kerberos v5 TGT forwarded (%s).", pname);
+               xfree(pname);
+       } else
+               debug("Kerberos v5 TGT forwarding failed.");
+       
+       return;
+       
+ out:
+       if (problem)
+               debug("Kerberos v5 TGT forwarding failed: %s",
+                   krb5_get_err_text(context, problem));
+       if (creds.client)
+               krb5_free_principal(context, creds.client);
+       if (creds.server)
+               krb5_free_principal(context, creds.server);
+       if (ccache)
+               krb5_cc_close(context, ccache);
+       if (outbuf.data)
+               xfree(outbuf.data);
+}
+#endif /* KRB5 */
+
+#ifdef AFS
+static void
+send_krb4_tgt(void)
+{
+       CREDENTIALS *creds;
+       struct stat st;
+       char buffer[4096], pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
+       int problem, type, len;
+       
+       /* Don't do anything if we don't have any tickets. */
+       if (stat(tkt_string(), &st) < 0)
+               return;
+       
+       creds = xmalloc(sizeof(*creds));
+       
+       problem = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm);
+       if (problem)
+               goto out;
+       
+       problem = krb_get_cred("krbtgt", prealm, prealm, creds);
+       if (problem)
+               goto out;
+       
+       if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
+               problem = RD_AP_EXP;
+               goto out;
+       }
+       creds_to_radix(creds, (u_char *)buffer, sizeof(buffer));
+       
+       packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
+       packet_put_cstring(buffer);
+       packet_send();
+       packet_write_wait();
+       
+       type = packet_read(&len);
+       
+       if (type == SSH_SMSG_SUCCESS)
+               debug("Kerberos v4 TGT forwarded (%s%s%s@%s).",
+                   creds->pname, creds->pinst[0] ? "." : "",
+                   creds->pinst, creds->realm);
+       else
+               debug("Kerberos v4 TGT rejected.");
+       
+       xfree(creds);
+       return;
+       
+ out:
+       debug("Kerberos v4 TGT passing failed: %s", krb_err_txt[problem]);
+       xfree(creds);
+}
+
+static void
+send_afs_tokens(void)
+{
+       CREDENTIALS creds;
+       struct ViceIoctl parms;
+       struct ClearToken ct;
+       int i, type, len;
+       char buf[2048], *p, *server_cell;
+       char buffer[8192];
+       
+       /* Move over ktc_GetToken, here's something leaner. */
+       for (i = 0; i < 100; i++) {     /* just in case */
+               parms.in = (char *) &i;
+               parms.in_size = sizeof(i);
+               parms.out = buf;
+               parms.out_size = sizeof(buf);
+               if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0)
+                       break;
+               p = buf;
+               
+               /* Get secret token. */
+               memcpy(&creds.ticket_st.length, p, sizeof(u_int));
+               if (creds.ticket_st.length > MAX_KTXT_LEN)
+                       break;
+               p += sizeof(u_int);
+               memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
+               p += creds.ticket_st.length;
+               
+               /* Get clear token. */
+               memcpy(&len, p, sizeof(len));
+               if (len != sizeof(struct ClearToken))
+                       break;
+               p += sizeof(len);
+               memcpy(&ct, p, len);
+               p += len;
+               p += sizeof(len);       /* primary flag */
+               server_cell = p;
+               
+               /* Flesh out our credentials. */
+               strlcpy(creds.service, "afs", sizeof(creds.service));
+               creds.instance[0] = '\0';
+               strlcpy(creds.realm, server_cell, REALM_SZ);
+               memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
+               creds.issue_date = ct.BeginTimestamp;
+               creds.lifetime = krb_time_to_life(creds.issue_date,
+                   ct.EndTimestamp);
+               creds.kvno = ct.AuthHandle;
+               snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
+               creds.pinst[0] = '\0';
+               
+               /* Encode token, ship it off. */
+               if (creds_to_radix(&creds, (u_char *)buffer,
+                   sizeof(buffer)) <= 0)
+                       break;
+               packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
+               packet_put_cstring(buffer);
+               packet_send();
+               packet_write_wait();
+
+               /* Roger, Roger. Clearance, Clarence. What's your vector,
+                  Victor? */
+               type = packet_read(&len);
+               
+               if (type == SSH_SMSG_FAILURE)
+                       debug("AFS token for cell %s rejected.", server_cell);
+               else if (type != SSH_SMSG_SUCCESS)
+                       packet_disconnect("Protocol error on AFS token response: %d", type);
+       }
+}
+
+#endif /* AFS */
+
+/*
+ * Tries to authenticate with any string-based challenge/response system.
+ * Note that the client code is not tied to s/key or TIS.
+ */
+static int
+try_challenge_response_authentication(void)
+{
+       int type, i;
+       int payload_len;
+       u_int clen;
+       char prompt[1024];
+       char *challenge, *response;
+
+       debug("Doing challenge response authentication.");
+
+       for (i = 0; i < options.number_of_password_prompts; i++) {
+               /* request a challenge */
+               packet_start(SSH_CMSG_AUTH_TIS);
+               packet_send();
+               packet_write_wait();
+
+               type = packet_read(&payload_len);
+               if (type != SSH_SMSG_FAILURE &&
+                   type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+                       packet_disconnect("Protocol error: got %d in response "
+                           "to SSH_CMSG_AUTH_TIS", type);
+               }
+               if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+                       debug("No challenge.");
+                       return 0;
+               }
+               challenge = packet_get_string(&clen);
+               packet_integrity_check(payload_len, (4 + clen), type);
+               snprintf(prompt, sizeof prompt, "%s%s", challenge,
+                    strchr(challenge, '\n') ? "" : "\nResponse: ");
+               xfree(challenge);
+               if (i != 0)
+                       error("Permission denied, please try again.");
+               if (options.cipher == SSH_CIPHER_NONE)
+                       log("WARNING: Encryption is disabled! "
+                           "Reponse will be transmitted in clear text.");
+               response = read_passphrase(prompt, 0);
+               if (strcmp(response, "") == 0) {
+                       xfree(response);
+                       break;
+               }
+               packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
+               ssh_put_password(response);
+               memset(response, 0, strlen(response));
+               xfree(response);
+               packet_send();
+               packet_write_wait();
+               type = packet_read(&payload_len);
+               if (type == SSH_SMSG_SUCCESS)
+                       return 1;
+               if (type != SSH_SMSG_FAILURE)
+                       packet_disconnect("Protocol error: got %d in response "
+                           "to SSH_CMSG_AUTH_TIS_RESPONSE", type);
+       }
+       /* failure */
+       return 0;
+}
+
+/*
+ * Tries to authenticate with plain passwd authentication.
+ */
+static int
+try_password_authentication(char *prompt)
+{
+       int type, i, payload_len;
+       char *password;
+
+       debug("Doing password authentication.");
+       if (options.cipher == SSH_CIPHER_NONE)
+               log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
+       for (i = 0; i < options.number_of_password_prompts; i++) {
+               if (i != 0)
+                       error("Permission denied, please try again.");
+               password = read_passphrase(prompt, 0);
+               packet_start(SSH_CMSG_AUTH_PASSWORD);
+               ssh_put_password(password);
+               memset(password, 0, strlen(password));
+               xfree(password);
+               packet_send();
+               packet_write_wait();
+
+               type = packet_read(&payload_len);
+               if (type == SSH_SMSG_SUCCESS)
+                       return 1;
+               if (type != SSH_SMSG_FAILURE)
+                       packet_disconnect("Protocol error: got %d in response to passwd auth", type);
+       }
+       /* failure */
+       return 0;
+}
+
+/*
+ * SSH1 key exchange
+ */
+void
+ssh_kex(char *host, struct sockaddr *hostaddr)
+{
+       int i;
+       BIGNUM *key;
+       RSA *host_key;
+       RSA *public_key;
+       Key k;
+       int bits, rbits;
+       int ssh_cipher_default = SSH_CIPHER_3DES;
+       u_char session_key[SSH_SESSION_KEY_LENGTH];
+       u_char cookie[8];
+       u_int supported_ciphers;
+       u_int server_flags, client_flags;
+       int payload_len, clen, sum_len = 0;
+       u_int32_t rand = 0;
+
+       debug("Waiting for server public key.");
+
+       /* Wait for a public key packet from the server. */
+       packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
+
+       /* Get cookie from the packet. */
+       for (i = 0; i < 8; i++)
+               cookie[i] = packet_get_char();
+
+       /* Get the public key. */
+       public_key = RSA_new();
+       bits = packet_get_int();/* bits */
+       public_key->e = BN_new();
+       packet_get_bignum(public_key->e, &clen);
+       sum_len += clen;
+       public_key->n = BN_new();
+       packet_get_bignum(public_key->n, &clen);
+       sum_len += clen;
+
+       rbits = BN_num_bits(public_key->n);
+       if (bits != rbits) {
+               log("Warning: Server lies about size of server public key: "
+                   "actual size is %d bits vs. announced %d.", rbits, bits);
+               log("Warning: This may be due to an old implementation of ssh.");
+       }
+       /* Get the host key. */
+       host_key = RSA_new();
+       bits = packet_get_int();/* bits */
+       host_key->e = BN_new();
+       packet_get_bignum(host_key->e, &clen);
+       sum_len += clen;
+       host_key->n = BN_new();
+       packet_get_bignum(host_key->n, &clen);
+       sum_len += clen;
+
+       rbits = BN_num_bits(host_key->n);
+       if (bits != rbits) {
+               log("Warning: Server lies about size of server host key: "
+                   "actual size is %d bits vs. announced %d.", rbits, bits);
+               log("Warning: This may be due to an old implementation of ssh.");
+       }
+
+       /* Get protocol flags. */
+       server_flags = packet_get_int();
+       packet_set_protocol_flags(server_flags);
+
+       supported_ciphers = packet_get_int();
+       supported_authentications = packet_get_int();
+
+       debug("Received server public key (%d bits) and host key (%d bits).",
+             BN_num_bits(public_key->n), BN_num_bits(host_key->n));
+
+       packet_integrity_check(payload_len,
+                              8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
+                              SSH_SMSG_PUBLIC_KEY);
+       k.type = KEY_RSA1;
+       k.rsa = host_key;
+       if (verify_host_key(host, hostaddr, &k) == -1)
+               fatal("Host key verification failed.");
+
+       client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
+
+       compute_session_id(session_id, cookie, host_key->n, public_key->n);
+
+       /* Generate a session key. */
+       arc4random_stir();
+
+       /*
+        * Generate an encryption key for the session.   The key is a 256 bit
+        * random number, interpreted as a 32-byte key, with the least
+        * significant 8 bits being the first byte of the key.
+        */
+       for (i = 0; i < 32; i++) {
+               if (i % 4 == 0)
+                       rand = arc4random();
+               session_key[i] = rand & 0xff;
+               rand >>= 8;
+       }
+
+       /*
+        * According to the protocol spec, the first byte of the session key
+        * is the highest byte of the integer.  The session key is xored with
+        * the first 16 bytes of the session id.
+        */
+       key = BN_new();
+       BN_set_word(key, 0);
+       for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+               BN_lshift(key, key, 8);
+               if (i < 16)
+                       BN_add_word(key, session_key[i] ^ session_id[i]);
+               else
+                       BN_add_word(key, session_key[i]);
+       }
+
+       /*
+        * Encrypt the integer using the public key and host key of the
+        * server (key with smaller modulus first).
+        */
+       if (BN_cmp(public_key->n, host_key->n) < 0) {
+               /* Public key has smaller modulus. */
+               if (BN_num_bits(host_key->n) <
+                   BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
+                       fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
+                             "SSH_KEY_BITS_RESERVED %d",
+                             BN_num_bits(host_key->n),
+                             BN_num_bits(public_key->n),
+                             SSH_KEY_BITS_RESERVED);
+               }
+               rsa_public_encrypt(key, key, public_key);
+               rsa_public_encrypt(key, key, host_key);
+       } else {
+               /* Host key has smaller modulus (or they are equal). */
+               if (BN_num_bits(public_key->n) <
+                   BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
+                       fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
+                             "SSH_KEY_BITS_RESERVED %d",
+                             BN_num_bits(public_key->n),
+                             BN_num_bits(host_key->n),
+                             SSH_KEY_BITS_RESERVED);
+               }
+               rsa_public_encrypt(key, key, host_key);
+               rsa_public_encrypt(key, key, public_key);
+       }
+
+       /* Destroy the public keys since we no longer need them. */
+       RSA_free(public_key);
+       RSA_free(host_key);
+
+       if (options.cipher == SSH_CIPHER_NOT_SET) {
+               if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default))
+                       options.cipher = ssh_cipher_default;
+       } else if (options.cipher == SSH_CIPHER_ILLEGAL ||
+           !(cipher_mask_ssh1(1) & (1 << options.cipher))) {
+               log("No valid SSH1 cipher, using %.100s instead.",
+                   cipher_name(ssh_cipher_default));
+               options.cipher = ssh_cipher_default;
+       }
+       /* Check that the selected cipher is supported. */
+       if (!(supported_ciphers & (1 << options.cipher)))
+               fatal("Selected cipher type %.100s not supported by server.",
+                     cipher_name(options.cipher));
+
+       debug("Encryption type: %.100s", cipher_name(options.cipher));
+
+       /* Send the encrypted session key to the server. */
+       packet_start(SSH_CMSG_SESSION_KEY);
+       packet_put_char(options.cipher);
+
+       /* Send the cookie back to the server. */
+       for (i = 0; i < 8; i++)
+               packet_put_char(cookie[i]);
+
+       /* Send and destroy the encrypted encryption key integer. */
+       packet_put_bignum(key);
+       BN_clear_free(key);
+
+       /* Send protocol flags. */
+       packet_put_int(client_flags);
+
+       /* Send the packet now. */
+       packet_send();
+       packet_write_wait();
+
+       debug("Sent encrypted session key.");
+
+       /* Set the encryption key. */
+       packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
+
+       /* We will no longer need the session key here.  Destroy any extra copies. */
+       memset(session_key, 0, sizeof(session_key));
+
+       /*
+        * Expect a success message from the server.  Note that this message
+        * will be received in encrypted form.
+        */
+       packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
+
+       debug("Received encrypted confirmation.");
+}
+
+/*
+ * Authenticate user
+ */
+void
+ssh_userauth1(const char *local_user, const char *server_user, char *host,
+    Key **keys, int nkeys)
+{
+#ifdef KRB5
+       krb5_context context = NULL;
+       krb5_auth_context auth_context = NULL;
+#endif
+       int i, type;
+       int payload_len;
+       
+       if (supported_authentications == 0)
+               fatal("ssh_userauth1: server supports no auth methods");
+
+       /* Send the name of the user to log in as on the server. */
+       packet_start(SSH_CMSG_USER);
+       packet_put_cstring(server_user);
+       packet_send();
+       packet_write_wait();
+
+       /*
+        * The server should respond with success if no authentication is
+        * needed (the user has no password).  Otherwise the server responds
+        * with failure.
+        */
+       type = packet_read(&payload_len);
+
+       /* check whether the connection was accepted without authentication. */
+       if (type == SSH_SMSG_SUCCESS)
+               goto success;
+       if (type != SSH_SMSG_FAILURE)
+               packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type);
+       
+#ifdef KRB5
+       if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
+            options.kerberos_authentication) {
+               debug("Trying Kerberos v5 authentication.");
+               
+               if (try_krb5_authentication(&context, &auth_context)) {
+                       type = packet_read(&payload_len);
+                       if (type == SSH_SMSG_SUCCESS)
+                               goto success;
+                       if (type != SSH_SMSG_FAILURE)
+                               packet_disconnect("Protocol error: got %d in response to Kerberos v5 auth", type);
+               }
+       }
+#endif /* KRB5 */
+       
+#ifdef KRB4
+       if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
+           options.kerberos_authentication) {
+               debug("Trying Kerberos v4 authentication.");
+               
+               if (try_krb4_authentication()) {
+                       type = packet_read(&payload_len);
+                       if (type == SSH_SMSG_SUCCESS)
+                               goto success;
+                       if (type != SSH_SMSG_FAILURE)
+                               packet_disconnect("Protocol error: got %d in response to Kerberos v4 auth", type);
+               }
+       }
+#endif /* KRB4 */
+       
+       /*
+        * Use rhosts authentication if running in privileged socket and we
+        * do not wish to remain anonymous.
+        */
+       if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
+           options.rhosts_authentication) {
+               debug("Trying rhosts authentication.");
+               packet_start(SSH_CMSG_AUTH_RHOSTS);
+               packet_put_cstring(local_user);
+               packet_send();
+               packet_write_wait();
+
+               /* The server should respond with success or failure. */
+               type = packet_read(&payload_len);
+               if (type == SSH_SMSG_SUCCESS)
+                       goto success;
+               if (type != SSH_SMSG_FAILURE)
+                       packet_disconnect("Protocol error: got %d in response to rhosts auth",
+                                         type);
+       }
+       /*
+        * Try .rhosts or /etc/hosts.equiv authentication with RSA host
+        * authentication.
+        */
+       if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
+           options.rhosts_rsa_authentication) {
+               for (i = 0; i < nkeys; i++) {
+                       if (keys[i] != NULL && keys[i]->type == KEY_RSA1 &&
+                           try_rhosts_rsa_authentication(local_user, keys[i]))
+                               goto success;
+               }
+       }
+       /* Try RSA authentication if the server supports it. */
+       if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
+           options.rsa_authentication) {
+               /*
+                * Try RSA authentication using the authentication agent. The
+                * agent is tried first because no passphrase is needed for
+                * it, whereas identity files may require passphrases.
+                */
+               if (try_agent_authentication())
+                       goto success;
+
+               /* Try RSA authentication for each identity. */
+               for (i = 0; i < options.num_identity_files; i++)
+                       if (options.identity_keys[i] != NULL &&
+                           options.identity_keys[i]->type == KEY_RSA1 &&
+                           try_rsa_authentication(i))
+                               goto success;
+       }
+       /* Try challenge response authentication if the server supports it. */
+       if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
+           options.challenge_response_authentication && !options.batch_mode) {
+               if (try_challenge_response_authentication())
+                       goto success;
+       }
+       /* Try password authentication if the server supports it. */
+       if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
+           options.password_authentication && !options.batch_mode) {
+               char prompt[80];
+
+               snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
+                   server_user, host);
+               if (try_password_authentication(prompt))
+                       goto success;
+       }
+       /* All authentication methods have failed.  Exit with an error message. */
+       fatal("Permission denied.");
+       /* NOTREACHED */
+
+ success:
+#ifdef KRB5
+       /* Try Kerberos v5 TGT passing. */
+       if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+           options.kerberos_tgt_passing && context && auth_context) {
+               if (options.cipher == SSH_CIPHER_NONE)
+                       log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+               send_krb5_tgt(context, auth_context);
+       }
+       if (auth_context)
+               krb5_auth_con_free(context, auth_context);
+       if (context)
+               krb5_free_context(context);
+#endif
+       
+#ifdef AFS
+       /* Try Kerberos v4 TGT passing if the server supports it. */
+       if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+           options.kerberos_tgt_passing) {
+               if (options.cipher == SSH_CIPHER_NONE)
+                       log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+               send_krb4_tgt();
+       }
+       /* Try AFS token passing if the server supports it. */
+       if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
+           options.afs_token_passing && k_hasafs()) {
+               if (options.cipher == SSH_CIPHER_NONE)
+                       log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
+               send_afs_tokens();
+       }
+#endif /* AFS */
+
+       return; /* need statement after label */
+}
diff --git a/openssh/sshconnect2.c b/openssh/sshconnect2.c
new file mode 100644 (file)
index 0000000..3107885
--- /dev/null
@@ -0,0 +1,1013 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshconnect2.c,v 1.85 2001/11/07 16:03:17 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+#include <openssl/dh.h>
+#include <openssl/hmac.h>
+
+#include "ssh.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "packet.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "bufaux.h"
+#include "cipher.h"
+#include "kex.h"
+#include "myproposal.h"
+#include "key.h"
+#include "sshconnect.h"
+#include "authfile.h"
+#include "dh.h"
+#include "authfd.h"
+#include "log.h"
+#include "readconf.h"
+#include "readpass.h"
+#include "match.h"
+#include "dispatch.h"
+#include "canohost.h"
+
+/* import */
+extern char *client_version_string;
+extern char *server_version_string;
+extern Options options;
+
+/*
+ * SSH2 key exchange
+ */
+
+u_char *session_id2 = NULL;
+int session_id2_len = 0;
+
+char *xxx_host;
+struct sockaddr *xxx_hostaddr;
+
+Kex *xxx_kex = NULL;
+
+static int
+verify_host_key_callback(Key *hostkey)
+{
+       if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
+               fatal("Host key verification failed.");
+       return 0;
+}
+
+void
+ssh_kex2(char *host, struct sockaddr *hostaddr)
+{
+       Kex *kex;
+
+       xxx_host = host;
+       xxx_hostaddr = hostaddr;
+
+       if (options.ciphers == (char *)-1) {
+               log("No valid ciphers for protocol version 2 given, using defaults.");
+               options.ciphers = NULL;
+       }
+       if (options.ciphers != NULL) {
+               myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+               myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+       }
+       myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+           compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
+       myproposal[PROPOSAL_ENC_ALGS_STOC] =
+           compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
+       if (options.compression) {
+               myproposal[PROPOSAL_COMP_ALGS_CTOS] =
+               myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
+       } else {
+               myproposal[PROPOSAL_COMP_ALGS_CTOS] =
+               myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
+       }
+       if (options.macs != NULL) {
+               myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+               myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
+       }
+       if (options.hostkeyalgorithms != NULL)
+               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+                   options.hostkeyalgorithms;
+
+       /* start key exchange */
+       kex = kex_setup(myproposal);
+       kex->client_version_string=client_version_string;
+       kex->server_version_string=server_version_string;
+       kex->verify_host_key=&verify_host_key_callback;
+
+       xxx_kex = kex;
+
+       dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
+
+       session_id2 = kex->session_id;
+       session_id2_len = kex->session_id_len;
+
+#ifdef DEBUG_KEXDH
+       /* send 1st encrypted/maced/compressed message */
+       packet_start(SSH2_MSG_IGNORE);
+       packet_put_cstring("markus");
+       packet_send();
+       packet_write_wait();
+#endif
+       debug("done: ssh_kex2.");
+}
+
+/*
+ * Authenticate user
+ */
+
+typedef struct Authctxt Authctxt;
+typedef struct Authmethod Authmethod;
+
+typedef int sign_cb_fn(
+    Authctxt *authctxt, Key *key,
+    u_char **sigp, int *lenp, u_char *data, int datalen);
+
+struct Authctxt {
+       const char *server_user;
+       const char *local_user;
+       const char *host;
+       const char *service;
+       Authmethod *method;
+       int success;
+       char *authlist;
+       /* pubkey */
+       Key *last_key;
+       sign_cb_fn *last_key_sign;
+       int last_key_hint;
+       AuthenticationConnection *agent;
+       /* hostbased */
+       Key **keys;
+       int nkeys;
+       /* kbd-interactive */
+       int info_req_seen;
+};
+struct Authmethod {
+       char    *name;          /* string to compare against server's list */
+       int     (*userauth)(Authctxt *authctxt);
+       int     *enabled;       /* flag in option struct that enables method */
+       int     *batch_flag;    /* flag in option struct that disables method */
+};
+
+void   input_userauth_success(int type, int plen, void *ctxt);
+void   input_userauth_failure(int type, int plen, void *ctxt);
+void   input_userauth_banner(int type, int plen, void *ctxt);
+void   input_userauth_error(int type, int plen, void *ctxt);
+void   input_userauth_info_req(int type, int plen, void *ctxt);
+void   input_userauth_pk_ok(int type, int plen, void *ctxt);
+
+int    userauth_none(Authctxt *authctxt);
+int    userauth_pubkey(Authctxt *authctxt);
+int    userauth_passwd(Authctxt *authctxt);
+int    userauth_kbdint(Authctxt *authctxt);
+int    userauth_hostbased(Authctxt *authctxt);
+
+void   userauth(Authctxt *authctxt, char *authlist);
+
+static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
+static void clear_auth_state(Authctxt *);
+
+static Authmethod *authmethod_get(char *authlist);
+static Authmethod *authmethod_lookup(const char *name);
+static char *authmethods_get(void);
+
+Authmethod authmethods[] = {
+       {"hostbased",
+               userauth_hostbased,
+               &options.hostbased_authentication,
+               NULL},
+       {"publickey",
+               userauth_pubkey,
+               &options.pubkey_authentication,
+               NULL},
+       {"keyboard-interactive",
+               userauth_kbdint,
+               &options.kbd_interactive_authentication,
+               &options.batch_mode},
+       {"password",
+               userauth_passwd,
+               &options.password_authentication,
+               &options.batch_mode},
+       {"none",
+               userauth_none,
+               NULL,
+               NULL},
+       {NULL, NULL, NULL, NULL}
+};
+
+void
+ssh_userauth2(const char *local_user, const char *server_user, char *host,
+    Key **keys, int nkeys)
+{
+       Authctxt authctxt;
+       int type;
+       int plen;
+
+       if (options.challenge_response_authentication)
+               options.kbd_interactive_authentication = 1;
+
+       debug("send SSH2_MSG_SERVICE_REQUEST");
+       packet_start(SSH2_MSG_SERVICE_REQUEST);
+       packet_put_cstring("ssh-userauth");
+       packet_send();
+       packet_write_wait();
+       type = packet_read(&plen);
+       if (type != SSH2_MSG_SERVICE_ACCEPT) {
+               fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
+       }
+       if (packet_remaining() > 0) {
+               char *reply = packet_get_string(&plen);
+               debug("service_accept: %s", reply);
+               xfree(reply);
+       } else {
+               debug("buggy server: service_accept w/o service");
+       }
+       packet_done();
+       debug("got SSH2_MSG_SERVICE_ACCEPT");
+
+       if (options.preferred_authentications == NULL)
+               options.preferred_authentications = authmethods_get();
+
+       /* setup authentication context */
+       memset(&authctxt, 0, sizeof(authctxt));
+       authctxt.agent = ssh_get_authentication_connection();
+       authctxt.server_user = server_user;
+       authctxt.local_user = local_user;
+       authctxt.host = host;
+       authctxt.service = "ssh-connection";            /* service name */
+       authctxt.success = 0;
+       authctxt.method = authmethod_lookup("none");
+       authctxt.authlist = NULL;
+       authctxt.keys = keys;
+       authctxt.nkeys = nkeys;
+       authctxt.info_req_seen = 0;
+       if (authctxt.method == NULL)
+               fatal("ssh_userauth2: internal error: cannot send userauth none request");
+
+       /* initial userauth request */
+       userauth_none(&authctxt);
+
+       dispatch_init(&input_userauth_error);
+       dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
+       dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
+       dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
+       dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */
+
+       if (authctxt.agent != NULL)
+               ssh_close_authentication_connection(authctxt.agent);
+
+       debug("ssh-userauth2 successful: method %s", authctxt.method->name);
+}
+void
+userauth(Authctxt *authctxt, char *authlist)
+{
+       if (authlist == NULL) {
+               authlist = authctxt->authlist;
+       } else {
+               if (authctxt->authlist)
+                       xfree(authctxt->authlist);
+               authctxt->authlist = authlist;
+       }
+       for (;;) {
+               Authmethod *method = authmethod_get(authlist);
+               if (method == NULL)
+                       fatal("Permission denied (%s).", authlist);
+               authctxt->method = method;
+               if (method->userauth(authctxt) != 0) {
+                       debug2("we sent a %s packet, wait for reply", method->name);
+                       break;
+               } else {
+                       debug2("we did not send a packet, disable method");
+                       method->enabled = NULL;
+               }
+       }
+}
+void
+input_userauth_error(int type, int plen, void *ctxt)
+{
+       fatal("input_userauth_error: bad message during authentication: "
+          "type %d", type);
+}
+void
+input_userauth_banner(int type, int plen, void *ctxt)
+{
+       char *msg, *lang;
+       debug3("input_userauth_banner");
+       msg = packet_get_string(NULL);
+       lang = packet_get_string(NULL);
+       fprintf(stderr, "%s", msg);
+       xfree(msg);
+       xfree(lang);
+}
+void
+input_userauth_success(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       if (authctxt == NULL)
+               fatal("input_userauth_success: no authentication context");
+       if (authctxt->authlist)
+               xfree(authctxt->authlist);
+       clear_auth_state(authctxt);
+       authctxt->success = 1;                  /* break out */
+}
+void
+input_userauth_failure(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       char *authlist = NULL;
+       int partial;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_failure: no authentication context");
+
+       authlist = packet_get_string(NULL);
+       partial = packet_get_char();
+       packet_done();
+
+       if (partial != 0)
+               log("Authenticated with partial success.");
+       debug("authentications that can continue: %s", authlist);
+
+       clear_auth_state(authctxt);
+       userauth(authctxt, authlist);
+}
+void
+input_userauth_pk_ok(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Key *key = NULL;
+       Buffer b;
+       int alen, blen, sent = 0;
+       char *pkalg, *pkblob, *fp;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_pk_ok: no authentication context");
+       if (datafellows & SSH_BUG_PKOK) {
+               /* this is similar to SSH_BUG_PKAUTH */
+               debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
+               pkblob = packet_get_string(&blen);
+               buffer_init(&b);
+               buffer_append(&b, pkblob, blen);
+               pkalg = buffer_get_string(&b, &alen);
+               buffer_free(&b);
+       } else {
+               pkalg = packet_get_string(&alen);
+               pkblob = packet_get_string(&blen);
+       }
+       packet_done();
+
+       debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",
+           pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
+
+       do {
+               if (authctxt->last_key == NULL ||
+                   authctxt->last_key_sign == NULL) {
+                       debug("no last key or no sign cb");
+                       break;
+               }
+               if (key_type_from_name(pkalg) == KEY_UNSPEC) {
+                       debug("unknown pkalg %s", pkalg);
+                       break;
+               }
+               if ((key = key_from_blob(pkblob, blen)) == NULL) {
+                       debug("no key from blob. pkalg %s", pkalg);
+                       break;
+               }
+               fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+               debug2("input_userauth_pk_ok: fp %s", fp);
+               xfree(fp);
+               if (!key_equal(key, authctxt->last_key)) {
+                       debug("key != last_key");
+                       break;
+               }
+               sent = sign_and_send_pubkey(authctxt, key,
+                  authctxt->last_key_sign);
+       } while(0);
+
+       if (key != NULL)
+               key_free(key);
+       xfree(pkalg);
+       xfree(pkblob);
+
+       /* unregister */
+       clear_auth_state(authctxt);
+       dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
+
+       /* try another method if we did not send a packet*/
+       if (sent == 0)
+               userauth(authctxt, NULL);
+
+}
+
+int
+userauth_none(Authctxt *authctxt)
+{
+       /* initial userauth request */
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+       packet_send();
+       return 1;
+}
+
+int
+userauth_passwd(Authctxt *authctxt)
+{
+       static int attempt = 0;
+       char prompt[80];
+       char *password;
+
+       if (attempt++ >= options.number_of_password_prompts)
+               return 0;
+
+       if(attempt != 1)
+               error("Permission denied, please try again.");
+
+       snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
+           authctxt->server_user, authctxt->host);
+       password = read_passphrase(prompt, 0);
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+       packet_put_char(0);
+       packet_put_cstring(password);
+       memset(password, 0, strlen(password));
+       xfree(password);
+       packet_add_padding(64);
+       packet_send();
+       return 1;
+}
+
+static void
+clear_auth_state(Authctxt *authctxt)
+{
+       /* XXX clear authentication state */
+       if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
+               debug3("clear_auth_state: key_free %p", authctxt->last_key);
+               key_free(authctxt->last_key);
+       }
+       authctxt->last_key = NULL;
+       authctxt->last_key_hint = -2;
+       authctxt->last_key_sign = NULL;
+}
+
+static int
+sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
+{
+       Buffer b;
+       u_char *blob, *signature;
+       int bloblen, slen;
+       int skip = 0;
+       int ret = -1;
+       int have_sig = 1;
+
+       debug3("sign_and_send_pubkey");
+
+       if (key_to_blob(k, &blob, &bloblen) == 0) {
+               /* we cannot handle this key */
+               debug3("sign_and_send_pubkey: cannot handle key");
+               return 0;
+       }
+       /* data to be signed */
+       buffer_init(&b);
+       if (datafellows & SSH_OLD_SESSIONID) {
+               buffer_append(&b, session_id2, session_id2_len);
+               skip = session_id2_len;
+       } else {
+               buffer_put_string(&b, session_id2, session_id2_len);
+               skip = buffer_len(&b);
+       }
+       buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+       buffer_put_cstring(&b, authctxt->server_user);
+       buffer_put_cstring(&b,
+           datafellows & SSH_BUG_PKSERVICE ?
+           "ssh-userauth" :
+           authctxt->service);
+       if (datafellows & SSH_BUG_PKAUTH) {
+               buffer_put_char(&b, have_sig);
+       } else {
+               buffer_put_cstring(&b, authctxt->method->name);
+               buffer_put_char(&b, have_sig);
+               buffer_put_cstring(&b, key_ssh_name(k));
+       }
+       buffer_put_string(&b, blob, bloblen);
+
+       /* generate signature */
+       ret = (*sign_callback)(authctxt, k, &signature, &slen,
+           buffer_ptr(&b), buffer_len(&b));
+       if (ret == -1) {
+               xfree(blob);
+               buffer_free(&b);
+               return 0;
+       }
+#ifdef DEBUG_PK
+       buffer_dump(&b);
+#endif
+       if (datafellows & SSH_BUG_PKSERVICE) {
+               buffer_clear(&b);
+               buffer_append(&b, session_id2, session_id2_len);
+               skip = session_id2_len;
+               buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+               buffer_put_cstring(&b, authctxt->server_user);
+               buffer_put_cstring(&b, authctxt->service);
+               buffer_put_cstring(&b, authctxt->method->name);
+               buffer_put_char(&b, have_sig);
+               if (!(datafellows & SSH_BUG_PKAUTH))
+                       buffer_put_cstring(&b, key_ssh_name(k));
+               buffer_put_string(&b, blob, bloblen);
+       }
+       xfree(blob);
+
+       /* append signature */
+       buffer_put_string(&b, signature, slen);
+       xfree(signature);
+
+       /* skip session id and packet type */
+       if (buffer_len(&b) < skip + 1)
+               fatal("userauth_pubkey: internal error");
+       buffer_consume(&b, skip + 1);
+
+       /* put remaining data from buffer into packet */
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_raw(buffer_ptr(&b), buffer_len(&b));
+       buffer_free(&b);
+       packet_send();
+
+       return 1;
+}
+
+static int
+send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
+    int hint)
+{
+       u_char *blob;
+       int bloblen, have_sig = 0;
+
+       debug3("send_pubkey_test");
+
+       if (key_to_blob(k, &blob, &bloblen) == 0) {
+               /* we cannot handle this key */
+               debug3("send_pubkey_test: cannot handle key");
+               return 0;
+       }
+       /* register callback for USERAUTH_PK_OK message */
+       authctxt->last_key_sign = sign_callback;
+       authctxt->last_key_hint = hint;
+       authctxt->last_key = k;
+       dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
+
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+       packet_put_char(have_sig);
+       if (!(datafellows & SSH_BUG_PKAUTH))
+               packet_put_cstring(key_ssh_name(k));
+       packet_put_string(blob, bloblen);
+       xfree(blob);
+       packet_send();
+       return 1;
+}
+
+static Key *
+load_identity_file(char *filename)
+{
+       Key *private;
+       char prompt[300], *passphrase;
+       int quit, i;
+       struct stat st;
+
+       if (stat(filename, &st) < 0) {
+               debug3("no such identity: %s", filename);
+               return NULL;
+       }
+       private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);
+       if (private == NULL) {
+               if (options.batch_mode)
+                       return NULL;
+               snprintf(prompt, sizeof prompt,
+                    "Enter passphrase for key '%.100s': ", filename);
+               for (i = 0; i < options.number_of_password_prompts; i++) {
+                       passphrase = read_passphrase(prompt, 0);
+                       if (strcmp(passphrase, "") != 0) {
+                               private = key_load_private_type(KEY_UNSPEC, filename,
+                                   passphrase, NULL);
+                               quit = 0;
+                       } else {
+                               debug2("no passphrase given, try next key");
+                               quit = 1;
+                       }
+                       memset(passphrase, 0, strlen(passphrase));
+                       xfree(passphrase);
+                       if (private != NULL || quit)
+                               break;
+                       debug2("bad passphrase given, try again...");
+               }
+       }
+       return private;
+}
+
+static int
+identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       Key *private;
+       int idx, ret;
+
+       idx = authctxt->last_key_hint;
+       if (idx < 0)
+               return -1;
+
+       /* private key is stored in external hardware */
+       if (options.identity_keys[idx]->flags & KEY_FLAG_EXT) 
+               return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
+
+       private = load_identity_file(options.identity_files[idx]);
+       if (private == NULL)
+               return -1;
+       ret = key_sign(private, sigp, lenp, data, datalen);
+       key_free(private);
+       return ret;
+}
+
+static int
+agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
+}
+
+static int
+key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
+    u_char *data, int datalen)
+{
+       return key_sign(key, sigp, lenp, data, datalen);
+}
+
+static int
+userauth_pubkey_agent(Authctxt *authctxt)
+{
+       static int called = 0;
+       int ret = 0;
+       char *comment;
+       Key *k;
+
+       if (called == 0) {
+               if (ssh_get_num_identities(authctxt->agent, 2) == 0)
+                       debug2("userauth_pubkey_agent: no keys at all");
+               called = 1;
+       }
+       k = ssh_get_next_identity(authctxt->agent, &comment, 2);
+       if (k == NULL) {
+               debug2("userauth_pubkey_agent: no more keys");
+       } else {
+               debug("userauth_pubkey_agent: testing agent key %s", comment);
+               xfree(comment);
+               ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
+               if (ret == 0)
+                       key_free(k);
+       }
+       if (ret == 0)
+               debug2("userauth_pubkey_agent: no message sent");
+       return ret;
+}
+
+int
+userauth_pubkey(Authctxt *authctxt)
+{
+       static int idx = 0;
+       int sent = 0;
+       Key *key;
+       char *filename;
+
+       if (authctxt->agent != NULL) {
+               do {
+                       sent = userauth_pubkey_agent(authctxt);
+               } while(!sent && authctxt->agent->howmany > 0);
+       }
+       while (!sent && idx < options.num_identity_files) {
+               key = options.identity_keys[idx];
+               filename = options.identity_files[idx];
+               if (key == NULL) {
+                       debug("try privkey: %s", filename);
+                       key = load_identity_file(filename);
+                       if (key != NULL) {
+                               sent = sign_and_send_pubkey(authctxt, key,
+                                   key_sign_cb);
+                               key_free(key);
+                       }
+               } else if (key->type != KEY_RSA1) {
+                       debug("try pubkey: %s", filename);
+                       sent = send_pubkey_test(authctxt, key,
+                           identity_sign_cb, idx);
+               }
+               idx++;
+       }
+       return sent;
+}
+
+/*
+ * Send userauth request message specifying keyboard-interactive method.
+ */
+int
+userauth_kbdint(Authctxt *authctxt)
+{
+       static int attempt = 0;
+
+       if (attempt++ >= options.number_of_password_prompts)
+               return 0;
+       /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
+       if (attempt > 1 && !authctxt->info_req_seen) {
+               debug3("userauth_kbdint: disable: no info_req_seen");
+               dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
+               return 0;
+       }
+
+       debug2("userauth_kbdint");
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+       packet_put_cstring("");                                 /* lang */
+       packet_put_cstring(options.kbd_interactive_devices ?
+           options.kbd_interactive_devices : "");
+       packet_send();
+
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
+       return 1;
+}
+
+/*
+ * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
+ */
+void
+input_userauth_info_req(int type, int plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       char *name, *inst, *lang, *prompt, *response;
+       u_int num_prompts, i;
+       int echo = 0;
+
+       debug2("input_userauth_info_req");
+
+       if (authctxt == NULL)
+               fatal("input_userauth_info_req: no authentication context");
+
+       authctxt->info_req_seen = 1;
+
+       name = packet_get_string(NULL);
+       inst = packet_get_string(NULL);
+       lang = packet_get_string(NULL);
+       if (strlen(name) > 0)
+               log("%s", name);
+       if (strlen(inst) > 0)
+               log("%s", inst);
+       xfree(name);
+       xfree(inst);
+       xfree(lang);
+
+       num_prompts = packet_get_int();
+       /*
+        * Begin to build info response packet based on prompts requested.
+        * We commit to providing the correct number of responses, so if
+        * further on we run into a problem that prevents this, we have to
+        * be sure and clean this up and send a correct error response.
+        */
+       packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+       packet_put_int(num_prompts);
+
+       debug2("input_userauth_info_req: num_prompts %d", num_prompts);
+       for (i = 0; i < num_prompts; i++) {
+               prompt = packet_get_string(NULL);
+               echo = packet_get_char();
+
+               response = read_passphrase(prompt, echo ? RP_ECHO : 0);
+
+               packet_put_cstring(response);
+               memset(response, 0, strlen(response));
+               xfree(response);
+               xfree(prompt);
+       }
+       packet_done(); /* done with parsing incoming message. */
+
+       packet_add_padding(64);
+       packet_send();
+}
+
+/*
+ * this will be move to an external program (ssh-keysign) ASAP. ssh-keysign
+ * will be setuid-root and the sbit can be removed from /usr/bin/ssh.
+ */
+int
+userauth_hostbased(Authctxt *authctxt)
+{
+       Key *private = NULL;
+       Buffer b;
+       u_char *signature, *blob;
+       char *chost, *pkalg, *p;
+       const char *service;
+       u_int blen, slen;
+       int ok, i, len, found = 0;
+
+       /* check for a useful key */
+       for (i = 0; i < authctxt->nkeys; i++) {
+               private = authctxt->keys[i];
+               if (private && private->type != KEY_RSA1) {
+                       found = 1;
+                       /* we take and free the key */
+                       authctxt->keys[i] = NULL;
+                       break;
+               }
+       }
+       if (!found) {
+               debug("userauth_hostbased: no more client hostkeys");
+               return 0;
+       }
+       if (key_to_blob(private, &blob, &blen) == 0) {
+               key_free(private);
+               return 0;
+       }
+       /* figure out a name for the client host */
+       p = get_local_name(packet_get_connection_in());
+       if (p == NULL) {
+               error("userauth_hostbased: cannot get local ipaddr/name");
+               key_free(private);
+               return 0;
+       }
+       len = strlen(p) + 2;
+       chost = xmalloc(len);
+       strlcpy(chost, p, len);
+       strlcat(chost, ".", len);
+       debug2("userauth_hostbased: chost %s", chost);
+
+       service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
+           authctxt->service;
+       pkalg = xstrdup(key_ssh_name(private));
+       buffer_init(&b);
+       /* construct data */
+       buffer_put_string(&b, session_id2, session_id2_len);
+       buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+       buffer_put_cstring(&b, authctxt->server_user);
+       buffer_put_cstring(&b, service);
+       buffer_put_cstring(&b, authctxt->method->name);
+       buffer_put_cstring(&b, pkalg);
+       buffer_put_string(&b, blob, blen);
+       buffer_put_cstring(&b, chost);
+       buffer_put_cstring(&b, authctxt->local_user);
+#ifdef DEBUG_PK
+       buffer_dump(&b);
+#endif
+       ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
+       key_free(private);
+       buffer_free(&b);
+       if (ok != 0) {
+               error("key_sign failed");
+               xfree(chost);
+               xfree(pkalg);
+               return 0;
+       }
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+       packet_put_cstring(pkalg);
+       packet_put_string(blob, blen);
+       packet_put_cstring(chost);
+       packet_put_cstring(authctxt->local_user);
+       packet_put_string(signature, slen);
+       memset(signature, 's', slen);
+       xfree(signature);
+       xfree(chost);
+       xfree(pkalg);
+
+       packet_send();
+       return 1;
+}
+
+/* find auth method */
+
+/*
+ * given auth method name, if configurable options permit this method fill
+ * in auth_ident field and return true, otherwise return false.
+ */
+static int
+authmethod_is_enabled(Authmethod *method)
+{
+       if (method == NULL)
+               return 0;
+       /* return false if options indicate this method is disabled */
+       if  (method->enabled == NULL || *method->enabled == 0)
+               return 0;
+       /* return false if batch mode is enabled but method needs interactive mode */
+       if  (method->batch_flag != NULL && *method->batch_flag != 0)
+               return 0;
+       return 1;
+}
+
+static Authmethod *
+authmethod_lookup(const char *name)
+{
+       Authmethod *method = NULL;
+       if (name != NULL)
+               for (method = authmethods; method->name != NULL; method++)
+                       if (strcmp(name, method->name) == 0)
+                               return method;
+       debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
+       return NULL;
+}
+
+/* XXX internal state */
+static Authmethod *current = NULL;
+static char *supported = NULL;
+static char *preferred = NULL;
+/*
+ * Given the authentication method list sent by the server, return the
+ * next method we should try.  If the server initially sends a nil list,
+ * use a built-in default list.
+ */
+static Authmethod *
+authmethod_get(char *authlist)
+{
+
+       char *name = NULL;
+       int next;
+
+       /* Use a suitable default if we're passed a nil list.  */
+       if (authlist == NULL || strlen(authlist) == 0)
+               authlist = options.preferred_authentications;
+
+       if (supported == NULL || strcmp(authlist, supported) != 0) {
+               debug3("start over, passed a different list %s", authlist);
+               if (supported != NULL)
+                       xfree(supported);
+               supported = xstrdup(authlist);
+               preferred = options.preferred_authentications;
+               debug3("preferred %s", preferred);
+               current = NULL;
+       } else if (current != NULL && authmethod_is_enabled(current))
+               return current;
+
+       for (;;) {
+               if ((name = match_list(preferred, supported, &next)) == NULL) {
+                       debug("no more auth methods to try");
+                       current = NULL;
+                       return NULL;
+               }
+               preferred += next;
+               debug3("authmethod_lookup %s", name);
+               debug3("remaining preferred: %s", preferred);
+               if ((current = authmethod_lookup(name)) != NULL &&
+                   authmethod_is_enabled(current)) {
+                       debug3("authmethod_is_enabled %s", name);
+                       debug("next auth method to try is %s", name);
+                       return current;
+               }
+       }
+}
+
+
+#define        DELIM   ","
+
+static char *
+authmethods_get(void)
+{
+       Authmethod *method = NULL;
+       char buf[1024];
+
+       buf[0] = '\0';
+       for (method = authmethods; method->name != NULL; method++) {
+               if (authmethod_is_enabled(method)) {
+                       if (buf[0] != '\0')
+                               strlcat(buf, DELIM, sizeof buf);
+                       strlcat(buf, method->name, sizeof buf);
+               }
+       }
+       return xstrdup(buf);
+}
diff --git a/openssh/sshd.8 b/openssh/sshd.8
new file mode 100644 (file)
index 0000000..5a6624b
--- /dev/null
@@ -0,0 +1,1325 @@
+.\"  -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\"                    All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose.  Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell.  All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: sshd.8,v 1.154 2001/11/07 22:12:01 markus Exp $
+.Dd September 25, 1999
+.Dt SSHD 8
+.Os
+.Sh NAME
+.Nm sshd
+.Nd OpenSSH SSH daemon
+.Sh SYNOPSIS
+.Nm sshd
+.Op Fl deiqtD46
+.Op Fl b Ar bits
+.Op Fl f Ar config_file
+.Op Fl g Ar login_grace_time
+.Op Fl h Ar host_key_file
+.Op Fl k Ar key_gen_time
+.Op Fl p Ar port
+.Op Fl u Ar len
+.Sh DESCRIPTION
+.Nm
+(SSH Daemon) is the daemon program for
+.Xr ssh 1 .
+Together these programs replace rlogin and rsh, and
+provide secure encrypted communications between two untrusted hosts
+over an insecure network.
+The programs are intended to be as easy to
+install and use as possible.
+.Pp
+.Nm
+is the daemon that listens for connections from clients.
+It is normally started at boot from
+.Pa /etc/rc .
+It forks a new
+daemon for each incoming connection.
+The forked daemons handle
+key exchange, encryption, authentication, command execution,
+and data exchange.
+This implementation of
+.Nm
+supports both SSH protocol version 1 and 2 simultaneously.
+.Nm
+works as follows.
+.Pp
+.Ss SSH protocol version 1
+.Pp
+Each host has a host-specific RSA key
+(normally 1024 bits) used to identify the host.
+Additionally, when
+the daemon starts, it generates a server RSA key (normally 768 bits).
+This key is normally regenerated every hour if it has been used, and
+is never stored on disk.
+.Pp
+Whenever a client connects the daemon responds with its public
+host and server keys.
+The client compares the
+RSA host key against its own database to verify that it has not changed.
+The client then generates a 256 bit random number.
+It encrypts this
+random number using both the host key and the server key, and sends
+the encrypted number to the server.
+Both sides then use this
+random number as a session key which is used to encrypt all further
+communications in the session.
+The rest of the session is encrypted
+using a conventional cipher, currently Blowfish or 3DES, with 3DES
+being used by default.
+The client selects the encryption algorithm
+to use from those offered by the server.
+.Pp
+Next, the server and the client enter an authentication dialog.
+The client tries to authenticate itself using
+.Pa .rhosts
+authentication,
+.Pa .rhosts
+authentication combined with RSA host
+authentication, RSA challenge-response authentication, or password
+based authentication.
+.Pp
+Rhosts authentication is normally disabled
+because it is fundamentally insecure, but can be enabled in the server
+configuration file if desired.
+System security is not improved unless
+.Xr rshd 8 ,
+.Xr rlogind 8 ,
+and
+.Xr rexecd 8
+are disabled (thus completely disabling
+.Xr rlogin 1
+and
+.Xr rsh 1
+into the machine).
+.Pp
+.Ss SSH protocol version 2
+.Pp
+Version 2 works similarly:
+Each host has a host-specific key (RSA or DSA) used to identify the host.
+However, when the daemon starts, it does not generate a server key.
+Forward security is provided through a Diffie-Hellman key agreement.
+This key agreement results in a shared session key.
+.Pp
+The rest of the session is encrypted using a symmetric cipher, currently
+128 bit AES, Blowfish, 3DES, CAST128, Arcfour, 192 bit AES, or 256 bit AES.
+The client selects the encryption algorithm
+to use from those offered by the server.
+Additionally, session integrity is provided
+through a cryptographic message authentication code
+(hmac-sha1 or hmac-md5).
+.Pp
+Protocol version 2 provides a public key based
+user (PubkeyAuthentication) or
+client host (HostbasedAuthentication) authentication method,
+conventional password authentication and challenge response based methods.
+.Pp
+.Ss Command execution and data forwarding
+.Pp
+If the client successfully authenticates itself, a dialog for
+preparing the session is entered.
+At this time the client may request
+things like allocating a pseudo-tty, forwarding X11 connections,
+forwarding TCP/IP connections, or forwarding the authentication agent
+connection over the secure channel.
+.Pp
+Finally, the client either requests a shell or execution of a command.
+The sides then enter session mode.
+In this mode, either side may send
+data at any time, and such data is forwarded to/from the shell or
+command on the server side, and the user terminal in the client side.
+.Pp
+When the user program terminates and all forwarded X11 and other
+connections have been closed, the server sends command exit status to
+the client, and both sides exit.
+.Pp
+.Nm
+can be configured using command-line options or a configuration
+file.
+Command-line options override values specified in the
+configuration file.
+.Pp
+.Nm
+rereads its configuration file when it receives a hangup signal,
+.Dv SIGHUP ,
+by executing itself with the name it was started as, i.e.,
+.Pa /usr/sbin/sshd .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b Ar bits
+Specifies the number of bits in the ephemeral protocol version 1
+server key (default 768).
+.It Fl d
+Debug mode.
+The server sends verbose debug output to the system
+log, and does not put itself in the background.
+The server also will not fork and will only process one connection.
+This option is only intended for debugging for the server.
+Multiple -d options increase the debugging level.
+Maximum is 3.
+.It Fl e
+When this option is specified,
+.Nm
+will send the output to the standard error instead of the system log.
+.It Fl f Ar configuration_file
+Specifies the name of the configuration file.
+The default is
+.Pa /etc/sshd_config .
+.Nm
+refuses to start if there is no configuration file.
+.It Fl g Ar login_grace_time
+Gives the grace time for clients to authenticate themselves (default
+600 seconds).
+If the client fails to authenticate the user within
+this many seconds, the server disconnects and exits.
+A value of zero indicates no limit.
+.It Fl h Ar host_key_file
+Specifies the file from which the host key is read (default
+.Pa /etc/ssh_host_key ) .
+This option must be given if
+.Nm
+is not run as root (as the normal
+host file is normally not readable by anyone but root).
+It is possible to have multiple host key files for
+the different protocol versions and host key algorithms.
+.It Fl i
+Specifies that
+.Nm
+is being run from inetd.
+.Nm
+is normally not run
+from inetd because it needs to generate the server key before it can
+respond to the client, and this may take tens of seconds.
+Clients would have to wait too long if the key was regenerated every time.
+However, with small key sizes (e.g., 512) using
+.Nm
+from inetd may
+be feasible.
+.It Fl k Ar key_gen_time
+Specifies how often the ephemeral protocol version 1 server key is
+regenerated (default 3600 seconds, or one hour).
+The motivation for regenerating the key fairly
+often is that the key is not stored anywhere, and after about an hour,
+it becomes impossible to recover the key for decrypting intercepted
+communications even if the machine is cracked into or physically
+seized.
+A value of zero indicates that the key will never be regenerated.
+.It Fl p Ar port
+Specifies the port on which the server listens for connections
+(default 22).
+.It Fl q
+Quiet mode.
+Nothing is sent to the system log.
+Normally the beginning,
+authentication, and termination of each connection is logged.
+.It Fl t
+Test mode.
+Only check the validity of the configuration file and sanity of the keys.
+This is useful for updating 
+.Nm
+reliably as configuration options may change.
+.It Fl u Ar len
+This option is used to specify the size of the field
+in the
+.Li utmp
+structure that holds the remote host name.
+If the resolved host name is longer than
+.Ar len ,
+the dotted decimal value will be used instead.
+This allows hosts with very long host names that
+overflow this field to still be uniquely identified.
+Specifying
+.Fl u0
+indicates that only dotted decimal addresses
+should be put into the
+.Pa utmp
+file.
+.Fl u0
+is also be used to prevent
+.Nm
+from making DNS requests unless the authentication
+mechanism or configuration requires it.
+Authentication mechanisms that may require DNS include
+.Cm RhostsAuthentication ,
+.Cm RhostsRSAAuthentication ,
+.Cm HostbasedAuthentication
+and using a
+.Cm from="pattern-list"
+option in a key file.
+.It Fl D
+When this option is specified
+.Nm
+will not detach and does not become a daemon.
+This allows easy monitoring of
+.Nm sshd .
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.El
+.Sh CONFIGURATION FILE
+.Nm
+reads configuration data from
+.Pa /etc/sshd_config
+(or the file specified with
+.Fl f
+on the command line).
+The file contains keyword-argument pairs, one per line.
+Lines starting with
+.Ql #
+and empty lines are interpreted as comments.
+.Pp
+The possible
+keywords and their meanings are as follows (note that
+keywords are case-insensitive and arguments are case-sensitive):
+.Bl -tag -width Ds
+.It Cm AFSTokenPassing
+Specifies whether an AFS token may be forwarded to the server.
+Default is
+.Dq yes .
+.It Cm AllowGroups
+This keyword can be followed by a list of group names, separated
+by spaces.
+If specified, login is allowed only for users whose primary
+group or supplementary group list matches one of the patterns.
+.Ql \&*
+and
+.Ql ?
+can be used as
+wildcards in the patterns.
+Only group names are valid; a numerical group ID is not recognized.
+By default login is allowed regardless of the group list.
+.Pp
+.It Cm AllowTcpForwarding
+Specifies whether TCP forwarding is permitted.
+The default is
+.Dq yes .
+Note that disabling TCP forwarding does not improve security unless
+users are also denied shell access, as they can always install their
+own forwarders.
+.Pp
+.It Cm AllowUsers
+This keyword can be followed by a list of user names, separated
+by spaces.
+If specified, login is allowed only for users names that
+match one of the patterns.
+.Ql \&*
+and
+.Ql ?
+can be used as
+wildcards in the patterns.
+Only user names are valid; a numerical user ID is not recognized.
+By default login is allowed regardless of the user name.
+If the pattern takes the form USER@HOST then USER and HOST
+are separately checked, restricting logins to particular
+users from particular hosts.
+.Pp
+.It Cm AuthorizedKeysFile
+Specifies the file that contains the public keys that can be used
+for user authentication.
+.Cm AuthorizedKeysFile
+may contain tokens of the form %T which are substituted during connection
+set-up. The following tokens are defined: %% is replaced by a literal '%',
+%h is replaced by the home directory of the user being authenticated and
+%u is replaced by the username of that user.
+After expansion,
+.Cm AuthorizedKeysFile
+is taken to be an absolute path or one relative to the user's home
+directory.
+The default is
+.Dq .ssh/authorized_keys
+.It Cm Banner
+In some jurisdictions, sending a warning message before authentication
+may be relevant for getting legal protection.
+The contents of the specified file are sent to the remote user before
+authentication is allowed.
+This option is only available for protocol version 2.
+.Pp
+.It Cm ChallengeResponseAuthentication
+Specifies whether challenge response authentication is allowed.
+All authentication styles from
+.Xr login.conf 5
+are supported.
+The default is
+.Dq yes .
+.It Cm Ciphers
+Specifies the ciphers allowed for protocol version 2.
+Multiple ciphers must be comma-separated.
+The default is
+.Dq aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour.
+.It Cm ClientAliveInterval
+Sets a timeout interval in seconds after which if no data has been received
+from the client,
+.Nm
+will send a message through the encrypted
+channel to request a response from the client.
+The default
+is 0, indicating that these messages will not be sent to the client.
+This option applies to protocol version 2 only.
+.It Cm ClientAliveCountMax
+Sets the number of client alive messages (see above) which may be
+sent without
+.Nm
+receiving any messages back from the client. If this threshold is
+reached while client alive messages are being sent,
+.Nm
+will disconnect the client, terminating the session. It is important
+to note that the use of client alive messages is very different from
+.Cm KeepAlive
+(below). The client alive messages are sent through the
+encrypted channel and therefore will not be spoofable. The TCP keepalive
+option enabled by
+.Cm KeepAlive
+is spoofable. The client alive mechanism is valuable when the client or
+server depend on knowing when a connection has become inactive.
+.Pp
+The default value is 3. If
+.Cm ClientAliveInterval
+(above) is set to 15, and
+.Cm ClientAliveCountMax
+is left at the default, unresponsive ssh clients
+will be disconnected after approximately 45 seconds.
+.It Cm DenyGroups
+This keyword can be followed by a number of group names, separated
+by spaces.
+Users whose primary group or supplementary group list matches
+one of the patterns aren't allowed to log in.
+.Ql \&*
+and
+.Ql ?
+can be used as
+wildcards in the patterns.
+Only group names are valid; a numerical group ID is not recognized.
+By default login is allowed regardless of the group list.
+.Pp
+.It Cm DenyUsers
+This keyword can be followed by a number of user names, separated
+by spaces.
+Login is disallowed for user names that match one of the patterns.
+.Ql \&*
+and
+.Ql ?
+can be used as wildcards in the patterns.
+Only user names are valid; a numerical user ID is not recognized.
+By default login is allowed regardless of the user name.
+.It Cm GatewayPorts
+Specifies whether remote hosts are allowed to connect to ports
+forwarded for the client.
+By default,
+.Nm
+binds remote port forwardings to the loopback addresss.  This
+prevents other remote hosts from connecting to forwarded ports.
+.Cm GatewayPorts
+can be used to specify that
+.Nm
+should bind remote port forwardings to the wildcard address,
+thus allowing remote hosts to connect to forwarded ports.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm HostbasedAuthentication
+Specifies whether rhosts or /etc/hosts.equiv authentication together
+with successful public key client host authentication is allowed
+(hostbased authentication).
+This option is similar to
+.Cm RhostsRSAAuthentication
+and applies to protocol version 2 only.
+The default is
+.Dq no .
+.It Cm HostKey
+Specifies the file containing the private host keys (default
+.Pa /etc/ssh_host_key )
+used by SSH protocol versions 1 and 2.
+Note that
+.Nm
+will refuse to use a file if it is group/world-accessible.
+It is possible to have multiple host key files.
+.Dq rsa1
+keys are used for version 1 and
+.Dq dsa
+or
+.Dq rsa
+are used for version 2 of the SSH protocol.
+.It Cm IgnoreRhosts
+Specifies that
+.Pa .rhosts
+and
+.Pa .shosts
+files will not be used in
+.Cm RhostsAuthentication ,
+.Cm RhostsRSAAuthentication
+or
+.Cm HostbasedAuthentication .
+.Pp
+.Pa /etc/hosts.equiv
+and
+.Pa /etc/shosts.equiv
+are still used.
+The default is
+.Dq yes .
+.It Cm IgnoreUserKnownHosts
+Specifies whether
+.Nm
+should ignore the user's
+.Pa $HOME/.ssh/known_hosts
+during
+.Cm RhostsRSAAuthentication
+or
+.Cm HostbasedAuthentication .
+The default is
+.Dq no .
+.It Cm KeepAlive
+Specifies whether the system should send keepalive messages to the
+other side.
+If they are sent, death of the connection or crash of one
+of the machines will be properly noticed.
+However, this means that
+connections will die if the route is down temporarily, and some people
+find it annoying.
+On the other hand, if keepalives are not sent,
+sessions may hang indefinitely on the server, leaving
+.Dq ghost
+users and consuming server resources.
+.Pp
+The default is
+.Dq yes
+(to send keepalives), and the server will notice
+if the network goes down or the client host reboots.
+This avoids infinitely hanging sessions.
+.Pp
+To disable keepalives, the value should be set to
+.Dq no
+in both the server and the client configuration files.
+.It Cm KerberosAuthentication
+Specifies whether Kerberos authentication is allowed.
+This can be in the form of a Kerberos ticket, or if
+.Cm PasswordAuthentication
+is yes, the password provided by the user will be validated through
+the Kerberos KDC.
+To use this option, the server needs a
+Kerberos servtab which allows the verification of the KDC's identity.
+Default is
+.Dq yes .
+.It Cm KerberosOrLocalPasswd
+If set then if password authentication through Kerberos fails then
+the password will be validated via any additional local mechanism
+such as
+.Pa /etc/passwd .
+Default is
+.Dq yes .
+.It Cm KerberosTgtPassing
+Specifies whether a Kerberos TGT may be forwarded to the server.
+Default is
+.Dq no ,
+as this only works when the Kerberos KDC is actually an AFS kaserver.
+.It Cm KerberosTicketCleanup
+Specifies whether to automatically destroy the user's ticket cache
+file on logout.
+Default is
+.Dq yes .
+.It Cm KeyRegenerationInterval
+In protocol version 1, the ephemeral server key is automatically regenerated
+after this many seconds (if it has been used).
+The purpose of regeneration is to prevent
+decrypting captured sessions by later breaking into the machine and
+stealing the keys.
+The key is never stored anywhere.
+If the value is 0, the key is never regenerated.
+The default is 3600 (seconds).
+.It Cm ListenAddress
+Specifies the local addresses
+.Nm
+should listen on.
+The following forms may be used:
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Cm ListenAddress
+.Sm off
+.Ar host No | Ar IPv4_addr No | Ar IPv6_addr
+.Sm on
+.It
+.Cm ListenAddress
+.Sm off
+.Ar host No | Ar IPv4_addr No : Ar port
+.Sm on
+.It
+.Cm ListenAddress
+.Sm off
+.Oo
+.Ar host No | Ar IPv6_addr Oc : Ar port
+.Sm on
+.El
+.Pp
+If
+.Ar port
+is not specified,
+.Nm
+will listen on the address and all prior
+.Cm Port
+options specified. The default is to listen on all local
+addresses.  Multiple
+.Cm ListenAddress
+options are permitted. Additionally, any
+.Cm Port
+options must precede this option for non port qualified addresses.
+.It Cm LoginGraceTime
+The server disconnects after this time if the user has not
+successfully logged in.
+If the value is 0, there is no time limit.
+The default is 600 (seconds).
+.It Cm LogLevel
+Gives the verbosity level that is used when logging messages from
+.Nm sshd .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
+The default is INFO.
+Logging with level DEBUG violates the privacy of users
+and is not recommended.
+.It Cm MACs
+Specifies the available MAC (message authentication code) algorithms.
+The MAC algorithm is used in protocol version 2
+for data integrity protection.
+Multiple algorithms must be comma-separated.
+The default is
+.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
+.It Cm MaxStartups
+Specifies the maximum number of concurrent unauthenticated connections to the
+.Nm
+daemon.
+Additional connections will be dropped until authentication succeeds or the
+.Cm LoginGraceTime
+expires for a connection.
+The default is 10.
+.Pp
+Alternatively, random early drop can be enabled by specifying
+the three colon separated values
+.Dq start:rate:full
+(e.g., "10:30:60").
+.Nm
+will refuse connection attempts with a probability of
+.Dq rate/100
+(30%)
+if there are currently
+.Dq start
+(10)
+unauthenticated connections.
+The probability increases linearly and all connection attempts
+are refused if the number of unauthenticated connections reaches
+.Dq full
+(60).
+.It Cm PAMAuthenticationViaKbdInt
+Specifies whether PAM challenge response authentication is allowed. This
+allows the use of most PAM challenge response authentication modules, but 
+it will allow password authentication regardless of whether 
+.Cm PasswordAuthentication
+is disabled.
+The default is
+.Dq no .
+.It Cm PasswordAuthentication
+Specifies whether password authentication is allowed.
+The default is
+.Dq yes .
+.It Cm PermitEmptyPasswords
+When password authentication is allowed, it specifies whether the
+server allows login to accounts with empty password strings.
+The default is
+.Dq no .
+.It Cm PermitRootLogin
+Specifies whether root can login using
+.Xr ssh 1 .
+The argument must be
+.Dq yes ,
+.Dq without-password ,
+.Dq forced-commands-only
+or
+.Dq no .
+The default is
+.Dq yes .
+.Pp
+If this option is set to
+.Dq without-password
+password authentication is disabled for root.
+.Pp
+If this option is set to
+.Dq forced-commands-only
+root login with public key authentication will be allowed,
+but only if the
+.Ar command
+option has been specified
+(which may be useful for taking remote backups even if root login is
+normally not allowed). All other authentication methods are disabled
+for root.
+.Pp
+If this option is set to
+.Dq no
+root is not allowed to login.
+.It Cm PidFile
+Specifies the file that contains the process identifier of the
+.Nm
+daemon.
+The default is
+.Pa /var/run/sshd.pid .
+.It Cm Port
+Specifies the port number that
+.Nm
+listens on.
+The default is 22.
+Multiple options of this type are permitted.
+See also
+.Cm ListenAddress .
+.It Cm PrintLastLog
+Specifies whether
+.Nm
+should print the date and time when the user last logged in.
+The default is
+.Dq yes .
+.It Cm PrintMotd
+Specifies whether
+.Nm
+should print
+.Pa /etc/motd
+when a user logs in interactively.
+(On some systems it is also printed by the shell,
+.Pa /etc/profile ,
+or equivalent.)
+The default is
+.Dq yes .
+.It Cm Protocol
+Specifies the protocol versions
+.Nm
+should support.
+The possible values are
+.Dq 1
+and
+.Dq 2 .
+Multiple versions must be comma-separated.
+The default is
+.Dq 2,1 .
+.It Cm PubkeyAuthentication
+Specifies whether public key authentication is allowed.
+The default is
+.Dq yes .
+Note that this option applies to protocol version 2 only.
+.It Cm ReverseMappingCheck
+Specifies whether
+.Nm
+should try to verify the remote host name and check that
+the resolved host name for the remote IP address maps back to the
+very same IP address.
+The default is
+.Dq no .
+.It Cm RhostsAuthentication
+Specifies whether authentication using rhosts or /etc/hosts.equiv
+files is sufficient.
+Normally, this method should not be permitted because it is insecure.
+.Cm RhostsRSAAuthentication
+should be used
+instead, because it performs RSA-based host authentication in addition
+to normal rhosts or /etc/hosts.equiv authentication.
+The default is
+.Dq no .
+This option applies to protocol version 1 only.
+.It Cm RhostsRSAAuthentication
+Specifies whether rhosts or /etc/hosts.equiv authentication together
+with successful RSA host authentication is allowed.
+The default is
+.Dq no .
+This option applies to protocol version 1 only.
+.It Cm RSAAuthentication
+Specifies whether pure RSA authentication is allowed.
+The default is
+.Dq yes .
+This option applies to protocol version 1 only.
+.It Cm ServerKeyBits
+Defines the number of bits in the ephemeral protocol version 1 server key.
+The minimum value is 512, and the default is 768.
+.It Cm StrictModes
+Specifies whether
+.Nm
+should check file modes and ownership of the
+user's files and home directory before accepting login.
+This is normally desirable because novices sometimes accidentally leave their
+directory or files world-writable.
+The default is
+.Dq yes .
+.It Cm Subsystem
+Configures an external subsystem (e.g., file transfer daemon).
+Arguments should be a subsystem name and a command to execute upon subsystem
+request.
+The command
+.Xr sftp-server 8
+implements the
+.Dq sftp
+file transfer subsystem.
+By default no subsystems are defined.
+Note that this option applies to protocol version 2 only.
+.It Cm SyslogFacility
+Gives the facility code that is used when logging messages from
+.Nm sshd .
+The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
+LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
+The default is AUTH.
+.It Cm UseLogin
+Specifies whether
+.Xr login 1
+is used for interactive login sessions.
+The default is
+.Dq no .
+Note that
+.Xr login 1
+is never used for remote command execution.
+Note also, that if this is enabled,
+.Cm X11Forwarding
+will be disabled because
+.Xr login 1
+does not know how to handle
+.Xr xauth 1
+cookies.
+.It Cm X11DisplayOffset
+Specifies the first display number available for
+.Nm sshd Ns 's
+X11 forwarding.
+This prevents
+.Nm
+from interfering with real X11 servers.
+The default is 10.
+.It Cm X11Forwarding
+Specifies whether X11 forwarding is permitted.
+The default is
+.Dq no .
+Note that disabling X11 forwarding does not improve security in any
+way, as users can always install their own forwarders.
+X11 forwarding is automatically disabled if
+.Cm UseLogin
+is enabled.
+.It Cm XAuthLocation
+Specifies the location of the
+.Xr xauth 1
+program.
+The default is
+.Pa /usr/X11R6/bin/xauth .
+.El
+.Ss Time Formats
+.Pp
+.Nm
+command-line arguments and configuration file options that specify time
+may be expressed using a sequence of the form:
+.Sm off
+.Ar time Oo Ar qualifier Oc ,
+.Sm on
+where
+.Ar time
+is a positive integer value and
+.Ar qualifier
+is one of the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Cm <none>
+seconds
+.It Cm s | Cm S
+seconds
+.It Cm m | Cm M
+minutes
+.It Cm h | Cm H
+hours
+.It Cm d | Cm D
+days
+.It Cm w | Cm W
+weeks
+.El
+.Pp
+Each member of the sequence is added together to calculate
+the total time value.
+.Pp
+Time format examples:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It 600
+600 seconds (10 minutes)
+.It 10m
+10 minutes
+.It 1h30m
+1 hour 30 minutes (90 minutes)
+.El
+.Sh LOGIN PROCESS
+When a user successfully logs in,
+.Nm
+does the following:
+.Bl -enum -offset indent
+.It
+If the login is on a tty, and no command has been specified,
+prints last login time and
+.Pa /etc/motd
+(unless prevented in the configuration file or by
+.Pa $HOME/.hushlogin ;
+see the
+.Sx FILES
+section).
+.It
+If the login is on a tty, records login time.
+.It
+Checks
+.Pa /etc/nologin ;
+if it exists, prints contents and quits
+(unless root).
+.It
+Changes to run with normal user privileges.
+.It
+Sets up basic environment.
+.It
+Reads
+.Pa $HOME/.ssh/environment
+if it exists.
+.It
+Changes to user's home directory.
+.It
+If
+.Pa $HOME/.ssh/rc
+exists, runs it; else if
+.Pa /etc/sshrc
+exists, runs
+it; otherwise runs xauth.
+The
+.Dq rc
+files are given the X11
+authentication protocol and cookie in standard input.
+.It
+Runs user's shell or command.
+.El
+.Sh AUTHORIZED_KEYS FILE FORMAT
+.Pa $HOME/.ssh/authorized_keys
+is the default file that lists the public keys that are
+permitted for RSA authentication in protocol version 1
+and for public key authentication (PubkeyAuthentication)
+in protocol version 2.
+.Cm AuthorizedKeysFile
+may be used to specify an alternative file.
+.Pp
+Each line of the file contains one
+key (empty lines and lines starting with a
+.Ql #
+are ignored as
+comments).
+Each RSA public key consists of the following fields, separated by
+spaces: options, bits, exponent, modulus, comment.
+Each protocol version 2 public key consists of:
+options, keytype, base64 encoded key, comment.
+The options fields
+are optional; its presence is determined by whether the line starts
+with a number or not (the option field never starts with a number).
+The bits, exponent, modulus and comment fields give the RSA key for
+protocol version 1; the
+comment field is not used for anything (but may be convenient for the
+user to identify the key).
+For protocol version 2 the keytype is
+.Dq ssh-dss
+or
+.Dq ssh-rsa .
+.Pp
+Note that lines in this file are usually several hundred bytes long
+(because of the size of the RSA key modulus).
+You don't want to type them in; instead, copy the
+.Pa identity.pub ,
+.Pa id_dsa.pub
+or the
+.Pa id_rsa.pub
+file and edit it.
+.Pp
+The options (if present) consist of comma-separated option
+specifications.
+No spaces are permitted, except within double quotes.
+The following option specifications are supported (note
+that option keywords are case-insensitive):
+.Bl -tag -width Ds
+.It Cm from="pattern-list"
+Specifies that in addition to RSA authentication, the canonical name
+of the remote host must be present in the comma-separated list of
+patterns
+.Pf ( Ql *
+and
+.Ql ?
+serve as wildcards).
+The list may also contain
+patterns negated by prefixing them with
+.Ql ! ;
+if the canonical host name matches a negated pattern, the key is not accepted.
+The purpose
+of this option is to optionally increase security: RSA authentication
+by itself does not trust the network or name servers or anything (but
+the key); however, if somebody somehow steals the key, the key
+permits an intruder to log in from anywhere in the world.
+This additional option makes using a stolen key more difficult (name
+servers and/or routers would have to be compromised in addition to
+just the key).
+.It Cm command="command"
+Specifies that the command is executed whenever this key is used for
+authentication.
+The command supplied by the user (if any) is ignored.
+The command is run on a pty if the client requests a pty;
+otherwise it is run without a tty.
+If a 8-bit clean channel is required,
+one must not request a pty or should specify
+.Cm no-pty .
+A quote may be included in the command by quoting it with a backslash.
+This option might be useful
+to restrict certain RSA keys to perform just a specific operation.
+An example might be a key that permits remote backups but nothing else.
+Note that the client may specify TCP/IP and/or X11
+forwarding unless they are explicitly prohibited.
+Note that this option applies to shell, command or subsystem execution.
+.It Cm environment="NAME=value"
+Specifies that the string is to be added to the environment when
+logging in using this key.
+Environment variables set this way
+override other default environment values.
+Multiple options of this type are permitted.
+This option is automatically disabled if
+.Cm UseLogin
+is enabled.
+.It Cm no-port-forwarding
+Forbids TCP/IP forwarding when this key is used for authentication.
+Any port forward requests by the client will return an error.
+This might be used, e.g., in connection with the
+.Cm command
+option.
+.It Cm no-X11-forwarding
+Forbids X11 forwarding when this key is used for authentication.
+Any X11 forward requests by the client will return an error.
+.It Cm no-agent-forwarding
+Forbids authentication agent forwarding when this key is used for
+authentication.
+.It Cm no-pty
+Prevents tty allocation (a request to allocate a pty will fail).
+.It Cm permitopen="host:port"
+Limit local
+.Li ``ssh -L''
+port forwarding such that it may only connect to the specified host and
+port.
+IPv6 addresses can be specified with an alternative syntax:
+.Ar host/port .
+Multiple
+.Cm permitopen
+options may be applied separated by commas. No pattern matching is
+performed on the specified hostnames, they must be literal domains or
+addresses.
+.El
+.Ss Examples
+1024 33 12121.\|.\|.\|312314325 ylo@foo.bar
+.Pp
+from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula
+.Pp
+command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi
+.Pp
+permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23.\|.\|.\|2323
+.Sh SSH_KNOWN_HOSTS FILE FORMAT
+The
+.Pa /etc/ssh_known_hosts ,
+and
+.Pa $HOME/.ssh/known_hosts
+files contain host public keys for all known hosts.
+The global file should
+be prepared by the administrator (optional), and the per-user file is
+maintained automatically: whenever the user connects from an unknown host
+its key is added to the per-user file.
+.Pp
+Each line in these files contains the following fields: hostnames,
+bits, exponent, modulus, comment.
+The fields are separated by spaces.
+.Pp
+Hostnames is a comma-separated list of patterns ('*' and '?' act as
+wildcards); each pattern in turn is matched against the canonical host
+name (when authenticating a client) or against the user-supplied
+name (when authenticating a server).
+A pattern may also be preceded by
+.Ql !
+to indicate negation: if the host name matches a negated
+pattern, it is not accepted (by that line) even if it matched another
+pattern on the line.
+.Pp
+Bits, exponent, and modulus are taken directly from the RSA host key; they
+can be obtained, e.g., from
+.Pa /etc/ssh_host_key.pub .
+The optional comment field continues to the end of the line, and is not used.
+.Pp
+Lines starting with
+.Ql #
+and empty lines are ignored as comments.
+.Pp
+When performing host authentication, authentication is accepted if any
+matching line has the proper key.
+It is thus permissible (but not
+recommended) to have several lines or different host keys for the same
+names.
+This will inevitably happen when short forms of host names
+from different domains are put in the file.
+It is possible
+that the files contain conflicting information; authentication is
+accepted if valid information can be found from either file.
+.Pp
+Note that the lines in these files are typically hundreds of characters
+long, and you definitely don't want to type in the host keys by hand.
+Rather, generate them by a script
+or by taking
+.Pa /etc/ssh_host_key.pub
+and adding the host names at the front.
+.Ss Examples
+.Bd -literal
+closenet,.\|.\|.\|,130.233.208.41 1024 37 159.\|.\|.93 closenet.hut.fi
+cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234.....=
+.Ed
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa /etc/sshd_config
+Contains configuration data for
+.Nm sshd .
+This file should be writable by root only, but it is recommended
+(though not necessary) that it be world-readable.
+.It Pa /etc/ssh_host_key, /etc/ssh_host_dsa_key, /etc/ssh_host_rsa_key
+These three files contain the private parts of the host keys.
+These files should only be owned by root, readable only by root, and not
+accessible to others.
+Note that
+.Nm
+does not start if this file is group/world-accessible.
+.It Pa /etc/ssh_host_key.pub, /etc/ssh_host_dsa_key.pub, /etc/ssh_host_rsa_key.pub
+These three files contain the public parts of the host keys.
+These files should be world-readable but writable only by
+root.
+Their contents should match the respective private parts.
+These files are not
+really used for anything; they are provided for the convenience of
+the user so their contents can be copied to known hosts files.
+These files are created using
+.Xr ssh-keygen 1 .
+.It Pa /etc/moduli
+Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
+.It Pa /var/run/sshd.pid
+Contains the process ID of the
+.Nm
+listening for connections (if there are several daemons running
+concurrently for different ports, this contains the pid of the one
+started last).
+The content of this file is not sensitive; it can be world-readable.
+.It Pa $HOME/.ssh/authorized_keys
+Lists the public keys (RSA or DSA) that can be used to log into the user's account.
+This file must be readable by root (which may on some machines imply
+it being world-readable if the user's home directory resides on an NFS
+volume).
+It is recommended that it not be accessible by others.
+The format of this file is described above.
+Users will place the contents of their
+.Pa identity.pub ,
+.Pa id_dsa.pub
+and/or
+.Pa id_rsa.pub
+files into this file, as described in
+.Xr ssh-keygen 1 .
+.It Pa "/etc/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
+These files are consulted when using rhosts with RSA host
+authentication or protocol version 2 hostbased authentication
+to check the public key of the host.
+The key must be listed in one of these files to be accepted.
+The client uses the same files
+to verify that it is connecting to the correct remote host.
+These files should be writable only by root/the owner.
+.Pa /etc/ssh_known_hosts
+should be world-readable, and
+.Pa $HOME/.ssh/known_hosts
+can but need not be world-readable.
+.It Pa /etc/nologin
+If this file exists,
+.Nm
+refuses to let anyone except root log in.
+The contents of the file
+are displayed to anyone trying to log in, and non-root connections are
+refused.
+The file should be world-readable.
+.It Pa /etc/hosts.allow, /etc/hosts.deny
+Access controls that should be enforced by tcp-wrappers are defined here.
+Further details are described in
+.Xr hosts_access 5 .
+.It Pa $HOME/.rhosts
+This file contains host-username pairs, separated by a space, one per
+line.
+The given user on the corresponding host is permitted to log in
+without password.
+The same file is used by rlogind and rshd.
+The file must
+be writable only by the user; it is recommended that it not be
+accessible by others.
+.Pp
+If is also possible to use netgroups in the file.
+Either host or user
+name may be of the form +@groupname to specify all hosts or all users
+in the group.
+.It Pa $HOME/.shosts
+For ssh,
+this file is exactly the same as for
+.Pa .rhosts .
+However, this file is
+not used by rlogin and rshd, so using this permits access using SSH only.
+.It Pa /etc/hosts.equiv
+This file is used during
+.Pa .rhosts
+authentication.
+In the simplest form, this file contains host names, one per line.
+Users on
+those hosts are permitted to log in without a password, provided they
+have the same user name on both machines.
+The host name may also be
+followed by a user name; such users are permitted to log in as
+.Em any
+user on this machine (except root).
+Additionally, the syntax
+.Dq +@group
+can be used to specify netgroups.
+Negated entries start with
+.Ql \&- .
+.Pp
+If the client host/user is successfully matched in this file, login is
+automatically permitted provided the client and server user names are the
+same.
+Additionally, successful RSA host authentication is normally required.
+This file must be writable only by root; it is recommended
+that it be world-readable.
+.Pp
+.Sy "Warning: It is almost never a good idea to use user names in"
+.Pa hosts.equiv .
+Beware that it really means that the named user(s) can log in as
+.Em anybody ,
+which includes bin, daemon, adm, and other accounts that own critical
+binaries and directories.
+Using a user name practically grants the user root access.
+The only valid use for user names that I can think
+of is in negative entries.
+.Pp
+Note that this warning also applies to rsh/rlogin.
+.It Pa /etc/shosts.equiv
+This is processed exactly as
+.Pa /etc/hosts.equiv .
+However, this file may be useful in environments that want to run both
+rsh/rlogin and ssh.
+.It Pa $HOME/.ssh/environment
+This file is read into the environment at login (if it exists).
+It can only contain empty lines, comment lines (that start with
+.Ql # ) ,
+and assignment lines of the form name=value.
+The file should be writable
+only by the user; it need not be readable by anyone else.
+.It Pa $HOME/.ssh/rc
+If this file exists, it is run with /bin/sh after reading the
+environment files but before starting the user's shell or command.
+If X11 spoofing is in use, this will receive the "proto cookie" pair in
+standard input (and
+.Ev DISPLAY
+in environment).
+This must call
+.Xr xauth 1
+in that case.
+.Pp
+The primary purpose of this file is to run any initialization routines
+which may be needed before the user's home directory becomes
+accessible; AFS is a particular example of such an environment.
+.Pp
+This file will probably contain some initialization code followed by
+something similar to:
+.Bd -literal
+       if read proto cookie; then
+               echo add $DISPLAY $proto $cookie | xauth -q -
+       fi
+.Ed
+.Pp
+If this file does not exist,
+.Pa /etc/sshrc
+is run, and if that
+does not exist either, xauth is used to store the cookie.
+.Pp
+This file should be writable only by the user, and need not be
+readable by anyone else.
+.It Pa /etc/sshrc
+Like
+.Pa $HOME/.ssh/rc .
+This can be used to specify
+machine-specific login-time initializations globally.
+This file should be writable only by root, and should be world-readable.
+.El
+.Sh AUTHORS
+OpenSSH is a derivative of the original and free
+ssh 1.2.12 release by Tatu Ylonen.
+Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
+Theo de Raadt and Dug Song
+removed many bugs, re-added newer features and
+created OpenSSH.
+Markus Friedl contributed the support for SSH
+protocol versions 1.5 and 2.0.
+.Sh SEE ALSO
+.Xr scp 1 ,
+.Xr sftp 1 ,
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr login.conf 5 ,
+.Xr moduli 5 ,
+.Xr sftp-server 8
+.Rs
+.%A T. Ylonen
+.%A T. Kivinen
+.%A M. Saarinen
+.%A T. Rinne
+.%A S. Lehtinen
+.%T "SSH Protocol Architecture"
+.%N draft-ietf-secsh-architecture-09.txt
+.%D July 2001
+.%O work in progress material
+.Re
+.Rs
+.%A M. Friedl
+.%A N. Provos
+.%A W. A. Simpson
+.%T "Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol"
+.%N draft-ietf-secsh-dh-group-exchange-01.txt
+.%D April 2001
+.%O work in progress material
+.Re
diff --git a/openssh/sshd.c b/openssh/sshd.c
new file mode 100644 (file)
index 0000000..71a5c2c
--- /dev/null
@@ -0,0 +1,1488 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This program is the ssh daemon.  It listens for connections from clients,
+ * and performs authentication, executes use commands or shell, and forwards
+ * information to/from the application to the user client over an encrypted
+ * connection.  This can also handle forwarding of X11, TCP/IP, and
+ * authentication agent connections.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * SSH2 implementation:
+ *
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshd.c,v 1.209 2001/11/10 13:19:45 markus Exp $");
+
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/hmac.h>
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "sshpty.h"
+#include "packet.h"
+#include "mpaux.h"
+#include "log.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "buffer.h"
+#include "cipher.h"
+#include "kex.h"
+#include "key.h"
+#include "dh.h"
+#include "myproposal.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "atomicio.h"
+#include "canohost.h"
+#include "auth.h"
+#include "misc.h"
+#include "dispatch.h"
+#include "channels.h"
+
+#ifdef LIBWRAP
+#include <tcpd.h>
+#include <syslog.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif /* LIBWRAP */
+
+#ifndef O_NOCTTY
+#define O_NOCTTY       0
+#endif
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
+
+/* Server configuration options. */
+ServerOptions options;
+
+/* Name of the server configuration file. */
+char *config_file_name = _PATH_SERVER_CONFIG_FILE;
+
+/*
+ * Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
+ * Default value is AF_UNSPEC means both IPv4 and IPv6.
+ */
+#ifdef IPV4_DEFAULT
+int IPv4or6 = AF_INET;
+#else
+int IPv4or6 = AF_UNSPEC;
+#endif
+
+/*
+ * Debug mode flag.  This can be set on the command line.  If debug
+ * mode is enabled, extra debugging output will be sent to the system
+ * log, the daemon will not go to background, and will exit after processing
+ * the first connection.
+ */
+int debug_flag = 0;
+
+/* Flag indicating that the daemon should only test the configuration and keys. */
+int test_flag = 0;
+
+/* Flag indicating that the daemon is being started from inetd. */
+int inetd_flag = 0;
+
+/* Flag indicating that sshd should not detach and become a daemon. */
+int no_daemon_flag = 0;
+
+/* debug goes to stderr unless inetd_flag is set */
+int log_stderr = 0;
+
+/* Saved arguments to main(). */
+char **saved_argv;
+int saved_argc;
+
+/*
+ * The sockets that the server is listening; this is used in the SIGHUP
+ * signal handler.
+ */
+#define        MAX_LISTEN_SOCKS        16
+int listen_socks[MAX_LISTEN_SOCKS];
+int num_listen_socks = 0;
+
+/*
+ * the client's version string, passed by sshd2 in compat mode. if != NULL,
+ * sshd will skip the version-number exchange
+ */
+char *client_version_string = NULL;
+char *server_version_string = NULL;
+
+/* for rekeying XXX fixme */
+Kex *xxx_kex;
+
+/*
+ * Any really sensitive data in the application is contained in this
+ * structure. The idea is that this structure could be locked into memory so
+ * that the pages do not get written into swap.  However, there are some
+ * problems. The private key contains BIGNUMs, and we do not (in principle)
+ * have access to the internals of them, and locking just the structure is
+ * not very useful.  Currently, memory locking is not implemented.
+ */
+struct {
+       Key     *server_key;            /* ephemeral server key */
+       Key     *ssh1_host_key;         /* ssh1 host key */
+       Key     **host_keys;            /* all private host keys */
+       int     have_ssh1_key;
+       int     have_ssh2_key;
+       u_char  ssh1_cookie[SSH_SESSION_KEY_LENGTH];
+} sensitive_data;
+
+/*
+ * Flag indicating whether the RSA server key needs to be regenerated.
+ * Is set in the SIGALRM handler and cleared when the key is regenerated.
+ */
+int key_do_regen = 0;
+
+/* This is set to true when a signal is received. */
+int received_sighup = 0;
+int received_sigterm = 0;
+
+/* session identifier, used by RSA-auth */
+u_char session_id[16];
+
+/* same for ssh2 */
+u_char *session_id2 = NULL;
+int session_id2_len = 0;
+
+/* record remote hostname or ip */
+u_int utmp_len = MAXHOSTNAMELEN;
+
+/* Prototypes for various functions defined later in this file. */
+void destroy_sensitive_data(void);
+
+static void do_ssh1_kex(void);
+static void do_ssh2_kex(void);
+
+/*
+ * Close all listening sockets
+ */
+static void
+close_listen_socks(void)
+{
+       int i;
+       for (i = 0; i < num_listen_socks; i++)
+               close(listen_socks[i]);
+       num_listen_socks = -1;
+}
+
+/*
+ * Signal handler for SIGHUP.  Sshd execs itself when it receives SIGHUP;
+ * the effect is to reread the configuration file (and to regenerate
+ * the server key).
+ */
+static void
+sighup_handler(int sig)
+{
+       received_sighup = 1;
+       signal(SIGHUP, sighup_handler);
+}
+
+/*
+ * Called from the main program after receiving SIGHUP.
+ * Restarts the server.
+ */
+static void
+sighup_restart(void)
+{
+       log("Received SIGHUP; restarting.");
+       close_listen_socks();
+       execv(saved_argv[0], saved_argv);
+       log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno));
+       exit(1);
+}
+
+/*
+ * Generic signal handler for terminating signals in the master daemon.
+ */
+static void
+sigterm_handler(int sig)
+{
+       received_sigterm = sig;
+}
+
+/*
+ * SIGCHLD handler.  This is called whenever a child dies.  This will then
+ * reap any zombies left by exited children.
+ */
+static void
+main_sigchld_handler(int sig)
+{
+       int save_errno = errno;
+       int status;
+
+       while (waitpid(-1, &status, WNOHANG) > 0)
+               ;
+
+       signal(SIGCHLD, main_sigchld_handler);
+       errno = save_errno;
+}
+
+/*
+ * Signal handler for the alarm after the login grace period has expired.
+ */
+static void
+grace_alarm_handler(int sig)
+{
+       /* XXX no idea how fix this signal handler */
+
+       /* Close the connection. */
+       packet_close();
+
+       /* Log error and exit. */
+       fatal("Timeout before authentication for %s.", get_remote_ipaddr());
+}
+
+/*
+ * Signal handler for the key regeneration alarm.  Note that this
+ * alarm only occurs in the daemon waiting for connections, and it does not
+ * do anything with the private key or random state before forking.
+ * Thus there should be no concurrency control/asynchronous execution
+ * problems.
+ */
+static void
+generate_ephemeral_server_key(void)
+{
+       u_int32_t rand = 0;
+       int i;
+
+       verbose("Generating %s%d bit RSA key.",
+           sensitive_data.server_key ? "new " : "", options.server_key_bits);
+       if (sensitive_data.server_key != NULL)
+               key_free(sensitive_data.server_key);
+       sensitive_data.server_key = key_generate(KEY_RSA1,
+           options.server_key_bits);
+       verbose("RSA key generation complete.");
+
+       for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+               if (i % 4 == 0)
+                       rand = arc4random();
+               sensitive_data.ssh1_cookie[i] = rand & 0xff;
+               rand >>= 8;
+       }
+       arc4random_stir();
+}
+
+static void
+key_regeneration_alarm(int sig)
+{
+       int save_errno = errno;
+       signal(SIGALRM, SIG_DFL);
+       errno = save_errno;
+       key_do_regen = 1;
+}
+
+static void
+sshd_exchange_identification(int sock_in, int sock_out)
+{
+       int i, mismatch;
+       int remote_major, remote_minor;
+       int major, minor;
+       char *s;
+       char buf[256];                  /* Must not be larger than remote_version. */
+       char remote_version[256];       /* Must be at least as big as buf. */
+
+       if ((options.protocol & SSH_PROTO_1) &&
+           (options.protocol & SSH_PROTO_2)) {
+               major = PROTOCOL_MAJOR_1;
+               minor = 99;
+       } else if (options.protocol & SSH_PROTO_2) {
+               major = PROTOCOL_MAJOR_2;
+               minor = PROTOCOL_MINOR_2;
+       } else {
+               major = PROTOCOL_MAJOR_1;
+               minor = PROTOCOL_MINOR_1;
+       }
+       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
+       server_version_string = xstrdup(buf);
+
+       if (client_version_string == NULL) {
+               /* Send our protocol version identification. */
+               if (atomicio(write, sock_out, server_version_string, strlen(server_version_string))
+                   != strlen(server_version_string)) {
+                       log("Could not write ident string to %s", get_remote_ipaddr());
+                       fatal_cleanup();
+               }
+
+               /* Read other side's version identification. */
+               memset(buf, 0, sizeof(buf));
+               for (i = 0; i < sizeof(buf) - 1; i++) {
+                       if (atomicio(read, sock_in, &buf[i], 1) != 1) {
+                               log("Did not receive identification string from %s",
+                                   get_remote_ipaddr());
+                               fatal_cleanup();
+                       }
+                       if (buf[i] == '\r') {
+                               buf[i] = 0;
+                               /* Kludge for F-Secure Macintosh < 1.0.2 */
+                               if (i == 12 &&
+                                   strncmp(buf, "SSH-1.5-W1.0", 12) == 0)
+                                       break;
+                               continue;
+                       }
+                       if (buf[i] == '\n') {
+                               buf[i] = 0;
+                               break;
+                       }
+               }
+               buf[sizeof(buf) - 1] = 0;
+               client_version_string = xstrdup(buf);
+       }
+
+       /*
+        * Check that the versions match.  In future this might accept
+        * several versions and set appropriate flags to handle them.
+        */
+       if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n",
+           &remote_major, &remote_minor, remote_version) != 3) {
+               s = "Protocol mismatch.\n";
+               (void) atomicio(write, sock_out, s, strlen(s));
+               close(sock_in);
+               close(sock_out);
+               log("Bad protocol version identification '%.100s' from %s",
+                   client_version_string, get_remote_ipaddr());
+               fatal_cleanup();
+       }
+       debug("Client protocol version %d.%d; client software version %.100s",
+             remote_major, remote_minor, remote_version);
+
+       compat_datafellows(remote_version);
+
+       if (datafellows & SSH_BUG_SCANNER) {
+               log("scanned from %s with %s.  Don't panic.",
+                   get_remote_ipaddr(), client_version_string);
+               fatal_cleanup();
+       }
+
+       mismatch = 0;
+       switch(remote_major) {
+       case 1:
+               if (remote_minor == 99) {
+                       if (options.protocol & SSH_PROTO_2)
+                               enable_compat20();
+                       else
+                               mismatch = 1;
+                       break;
+               }
+               if (!(options.protocol & SSH_PROTO_1)) {
+                       mismatch = 1;
+                       break;
+               }
+               if (remote_minor < 3) {
+                       packet_disconnect("Your ssh version is too old and "
+                           "is no longer supported.  Please install a newer version.");
+               } else if (remote_minor == 3) {
+                       /* note that this disables agent-forwarding */
+                       enable_compat13();
+               }
+               break;
+       case 2:
+               if (options.protocol & SSH_PROTO_2) {
+                       enable_compat20();
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               mismatch = 1;
+               break;
+       }
+       chop(server_version_string);
+       debug("Local version string %.200s", server_version_string);
+
+       if (mismatch) {
+               s = "Protocol major versions differ.\n";
+               (void) atomicio(write, sock_out, s, strlen(s));
+               close(sock_in);
+               close(sock_out);
+               log("Protocol major versions differ for %s: %.200s vs. %.200s",
+                   get_remote_ipaddr(),
+                   server_version_string, client_version_string);
+               fatal_cleanup();
+       }
+}
+
+
+/* Destroy the host and server keys.  They will no longer be needed. */
+void
+destroy_sensitive_data(void)
+{
+       int i;
+
+       if (sensitive_data.server_key) {
+               key_free(sensitive_data.server_key);
+               sensitive_data.server_key = NULL;
+       }
+       for(i = 0; i < options.num_host_key_files; i++) {
+               if (sensitive_data.host_keys[i]) {
+                       key_free(sensitive_data.host_keys[i]);
+                       sensitive_data.host_keys[i] = NULL;
+               }
+       }
+       sensitive_data.ssh1_host_key = NULL;
+       memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
+}
+
+static char *
+list_hostkey_types(void)
+{
+       static char buf[1024];
+       int i;
+       buf[0] = '\0';
+       for(i = 0; i < options.num_host_key_files; i++) {
+               Key *key = sensitive_data.host_keys[i];
+               if (key == NULL)
+                       continue;
+               switch(key->type) {
+               case KEY_RSA:
+               case KEY_DSA:
+                       strlcat(buf, key_ssh_name(key), sizeof buf);
+                       strlcat(buf, ",", sizeof buf);
+                       break;
+               }
+       }
+       i = strlen(buf);
+       if (i > 0 && buf[i-1] == ',')
+               buf[i-1] = '\0';
+       debug("list_hostkey_types: %s", buf);
+       return buf;
+}
+
+static Key *
+get_hostkey_by_type(int type)
+{
+       int i;
+       for(i = 0; i < options.num_host_key_files; i++) {
+               Key *key = sensitive_data.host_keys[i];
+               if (key != NULL && key->type == type)
+                       return key;
+       }
+       return NULL;
+}
+
+/*
+ * returns 1 if connection should be dropped, 0 otherwise.
+ * dropping starts at connection #max_startups_begin with a probability
+ * of (max_startups_rate/100). the probability increases linearly until
+ * all connections are dropped for startups > max_startups
+ */
+static int
+drop_connection(int startups)
+{
+       double p, r;
+
+       if (startups < options.max_startups_begin)
+               return 0;
+       if (startups >= options.max_startups)
+               return 1;
+       if (options.max_startups_rate == 100)
+               return 1;
+
+       p  = 100 - options.max_startups_rate;
+       p *= startups - options.max_startups_begin;
+       p /= (double) (options.max_startups - options.max_startups_begin);
+       p += options.max_startups_rate;
+       p /= 100.0;
+       r = arc4random() / (double) UINT_MAX;
+
+       debug("drop_connection: p %g, r %g", p, r);
+       return (r < p) ? 1 : 0;
+}
+
+int *startup_pipes = NULL;     /* options.max_startup sized array of fd ints */
+int startup_pipe;              /* in child */
+
+/*
+ * Main program for the daemon.
+ */
+int
+main(int ac, char **av)
+{
+       extern char *optarg;
+       extern int optind;
+       int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
+       pid_t pid;
+       socklen_t fromlen;
+       fd_set *fdset;
+       struct sockaddr_storage from;
+       const char *remote_ip;
+       int remote_port;
+       FILE *f;
+       struct linger linger;
+       struct addrinfo *ai;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       int listen_sock, maxfd;
+       int startup_p[2];
+       int startups = 0;
+       Key *key;
+       int ret, key_used = 0;
+
+       __progname = get_progname(av[0]);
+       init_rng();
+
+       /* Save argv. */
+       saved_argc = ac;
+       saved_argv = av;
+
+       /* Initialize configuration options to their default values. */
+       initialize_server_options(&options);
+
+       /* Parse command-line arguments. */
+       while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDeiqtQ46")) != -1) {
+               switch (opt) {
+               case '4':
+                       IPv4or6 = AF_INET;
+                       break;
+               case '6':
+                       IPv4or6 = AF_INET6;
+                       break;
+               case 'f':
+                       config_file_name = optarg;
+                       break;
+               case 'd':
+                       if (0 == debug_flag) {
+                               debug_flag = 1;
+                               options.log_level = SYSLOG_LEVEL_DEBUG1;
+                       } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
+                               options.log_level++;
+                       } else {
+                               fprintf(stderr, "Too high debugging level.\n");
+                               exit(1);
+                       }
+                       break;
+               case 'D':
+                       no_daemon_flag = 1;
+                       break;
+               case 'e':
+                       log_stderr = 1;
+                       break;
+               case 'i':
+                       inetd_flag = 1;
+                       break;
+               case 'Q':
+                       /* ignored */
+                       break;
+               case 'q':
+                       options.log_level = SYSLOG_LEVEL_QUIET;
+                       break;
+               case 'b':
+                       options.server_key_bits = atoi(optarg);
+                       break;
+               case 'p':
+                       options.ports_from_cmdline = 1;
+                       if (options.num_ports >= MAX_PORTS) {
+                               fprintf(stderr, "too many ports.\n");
+                               exit(1);
+                       }
+                       options.ports[options.num_ports++] = a2port(optarg);
+                       if (options.ports[options.num_ports-1] == 0) {
+                               fprintf(stderr, "Bad port number.\n");
+                               exit(1);
+                       }
+                       break;
+               case 'g':
+                       if ((options.login_grace_time = convtime(optarg)) == -1) {
+                               fprintf(stderr, "Invalid login grace time.\n");
+                               exit(1);
+                       }
+                       break;
+               case 'k':
+                       if ((options.key_regeneration_time = convtime(optarg)) == -1) {
+                               fprintf(stderr, "Invalid key regeneration interval.\n");
+                               exit(1);
+                       }
+                       break;
+               case 'h':
+                       if (options.num_host_key_files >= MAX_HOSTKEYS) {
+                               fprintf(stderr, "too many host keys.\n");
+                               exit(1);
+                       }
+                       options.host_key_files[options.num_host_key_files++] = optarg;
+                       break;
+               case 'V':
+                       client_version_string = optarg;
+                       /* only makes sense with inetd_flag, i.e. no listen() */
+                       inetd_flag = 1;
+                       break;
+               case 't':
+                       test_flag = 1;
+                       break;
+               case 'u':
+                       utmp_len = atoi(optarg);
+                       break;
+               case '?':
+               default:
+                       fprintf(stderr, "sshd version %s\n", SSH_VERSION);
+                       fprintf(stderr, "Usage: %s [options]\n", __progname);
+                       fprintf(stderr, "Options:\n");
+                       fprintf(stderr, "  -f file    Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
+                       fprintf(stderr, "  -d         Debugging mode (multiple -d means more debugging)\n");
+                       fprintf(stderr, "  -i         Started from inetd\n");
+                       fprintf(stderr, "  -D         Do not fork into daemon mode\n");
+                       fprintf(stderr, "  -t         Only test configuration file and keys\n");
+                       fprintf(stderr, "  -q         Quiet (no logging)\n");
+                       fprintf(stderr, "  -p port    Listen on the specified port (default: 22)\n");
+                       fprintf(stderr, "  -k seconds Regenerate server key every this many seconds (default: 3600)\n");
+                       fprintf(stderr, "  -g seconds Grace period for authentication (default: 600)\n");
+                       fprintf(stderr, "  -b bits    Size of server RSA key (default: 768 bits)\n");
+                       fprintf(stderr, "  -h file    File from which to read host key (default: %s)\n",
+                           _PATH_HOST_KEY_FILE);
+                       fprintf(stderr, "  -u len     Maximum hostname length for utmp recording\n");
+                       fprintf(stderr, "  -4         Use IPv4 only\n");
+                       fprintf(stderr, "  -6         Use IPv6 only\n");
+                       exit(1);
+               }
+       }
+       SSLeay_add_all_algorithms();
+       channel_set_af(IPv4or6);
+
+       /*
+        * Force logging to stderr until we have loaded the private host
+        * key (unless started from inetd)
+        */
+       log_init(__progname,
+           options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
+           options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
+           !inetd_flag);
+
+#ifdef _CRAY
+       /* Cray can define user privs drop all prives now!
+        * Not needed on PRIV_SU systems!
+        */
+       drop_cray_privs();
+#endif
+
+       seed_rng();
+
+       /* Read server configuration options from the configuration file. */
+       read_server_config(&options, config_file_name);
+
+       /* Fill in default values for those options not explicitly set. */
+       fill_default_server_options(&options);
+
+       /* Check that there are no remaining arguments. */
+       if (optind < ac) {
+               fprintf(stderr, "Extra argument %s.\n", av[optind]);
+               exit(1);
+       }
+
+       debug("sshd version %.100s", SSH_VERSION);
+
+       /* load private host keys */
+       sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*));
+       for(i = 0; i < options.num_host_key_files; i++)
+               sensitive_data.host_keys[i] = NULL;
+       sensitive_data.server_key = NULL;
+       sensitive_data.ssh1_host_key = NULL;
+       sensitive_data.have_ssh1_key = 0;
+       sensitive_data.have_ssh2_key = 0;
+
+       for(i = 0; i < options.num_host_key_files; i++) {
+               key = key_load_private(options.host_key_files[i], "", NULL);
+               sensitive_data.host_keys[i] = key;
+               if (key == NULL) {
+                       error("Could not load host key: %s",
+                           options.host_key_files[i]);
+                       sensitive_data.host_keys[i] = NULL;
+                       continue;
+               }
+               switch(key->type){
+               case KEY_RSA1:
+                       sensitive_data.ssh1_host_key = key;
+                       sensitive_data.have_ssh1_key = 1;
+                       break;
+               case KEY_RSA:
+               case KEY_DSA:
+                       sensitive_data.have_ssh2_key = 1;
+                       break;
+               }
+               debug("private host key: #%d type %d %s", i, key->type,
+                   key_type(key));
+       }
+       if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
+               log("Disabling protocol version 1. Could not load host key");
+               options.protocol &= ~SSH_PROTO_1;
+       }
+       if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
+               log("Disabling protocol version 2. Could not load host key");
+               options.protocol &= ~SSH_PROTO_2;
+       }
+       if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
+               log("sshd: no hostkeys available -- exiting.");
+               exit(1);
+       }
+
+       /* Check certain values for sanity. */
+       if (options.protocol & SSH_PROTO_1) {
+               if (options.server_key_bits < 512 ||
+                   options.server_key_bits > 32768) {
+                       fprintf(stderr, "Bad server key size.\n");
+                       exit(1);
+               }
+               /*
+                * Check that server and host key lengths differ sufficiently. This
+                * is necessary to make double encryption work with rsaref. Oh, I
+                * hate software patents. I dont know if this can go? Niels
+                */
+               if (options.server_key_bits >
+                   BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - SSH_KEY_BITS_RESERVED &&
+                   options.server_key_bits <
+                   BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+                       options.server_key_bits =
+                           BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED;
+                       debug("Forcing server key to %d bits to make it differ from host key.",
+                           options.server_key_bits);
+               }
+       }
+
+       /* Configuration looks good, so exit if in test mode. */
+       if (test_flag)
+               exit(0);
+
+#ifdef HAVE_SCO_PROTECTED_PW
+       (void) set_auth_parameters(ac, av);
+#endif
+
+       /* Initialize the log (it is reinitialized below in case we forked). */
+       if (debug_flag && !inetd_flag)
+               log_stderr = 1;
+       log_init(__progname, options.log_level, options.log_facility, log_stderr);
+
+       /*
+        * If not in debugging mode, and not started from inetd, disconnect
+        * from the controlling terminal, and fork.  The original process
+        * exits.
+        */
+       if (!(debug_flag || inetd_flag || no_daemon_flag)) {
+#ifdef TIOCNOTTY
+               int fd;
+#endif /* TIOCNOTTY */
+               if (daemon(0, 0) < 0)
+                       fatal("daemon() failed: %.200s", strerror(errno));
+
+               /* Disconnect from the controlling tty. */
+#ifdef TIOCNOTTY
+               fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
+               if (fd >= 0) {
+                       (void) ioctl(fd, TIOCNOTTY, NULL);
+                       close(fd);
+               }
+#endif /* TIOCNOTTY */
+       }
+       /* Reinitialize the log (because of the fork above). */
+       log_init(__progname, options.log_level, options.log_facility, log_stderr);
+
+       /* Initialize the random number generator. */
+       arc4random_stir();
+
+       /* Chdir to the root directory so that the current disk can be
+          unmounted if desired. */
+       chdir("/");
+       
+       /* ignore SIGPIPE */
+       signal(SIGPIPE, SIG_IGN);
+
+       /* Start listening for a socket, unless started from inetd. */
+       if (inetd_flag) {
+               int s1;
+               s1 = dup(0);    /* Make sure descriptors 0, 1, and 2 are in use. */
+               dup(s1);
+               sock_in = dup(0);
+               sock_out = dup(1);
+               startup_pipe = -1;
+               /*
+                * We intentionally do not close the descriptors 0, 1, and 2
+                * as our code for setting the descriptors won\'t work if
+                * ttyfd happens to be one of those.
+                */
+               debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
+               if (options.protocol & SSH_PROTO_1)
+                       generate_ephemeral_server_key();
+       } else {
+               for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
+                       if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                               continue;
+                       if (num_listen_socks >= MAX_LISTEN_SOCKS)
+                               fatal("Too many listen sockets. "
+                                   "Enlarge MAX_LISTEN_SOCKS");
+                       if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                           ntop, sizeof(ntop), strport, sizeof(strport),
+                           NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                               error("getnameinfo failed");
+                               continue;
+                       }
+                       /* Create socket for listening. */
+                       listen_sock = socket(ai->ai_family, SOCK_STREAM, 0);
+                       if (listen_sock < 0) {
+                               /* kernel may not support ipv6 */
+                               verbose("socket: %.100s", strerror(errno));
+                               continue;
+                       }
+                       if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) {
+                               error("listen_sock O_NONBLOCK: %s", strerror(errno));
+                               close(listen_sock);
+                               continue;
+                       }
+                       /*
+                        * Set socket options.  We try to make the port
+                        * reusable and have it close as fast as possible
+                        * without waiting in unnecessary wait states on
+                        * close.
+                        */
+                       setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
+                           (void *) &on, sizeof(on));
+                       linger.l_onoff = 1;
+                       linger.l_linger = 5;
+                       setsockopt(listen_sock, SOL_SOCKET, SO_LINGER,
+                           (void *) &linger, sizeof(linger));
+
+                       debug("Bind to port %s on %s.", strport, ntop);
+
+                       /* Bind the socket to the desired port. */
+                       if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                               if (!ai->ai_next)
+                                   error("Bind to port %s on %s failed: %.200s.",
+                                           strport, ntop, strerror(errno));
+                               close(listen_sock);
+                               continue;
+                       }
+                       listen_socks[num_listen_socks] = listen_sock;
+                       num_listen_socks++;
+
+                       /* Start listening on the port. */
+                       log("Server listening on %s port %s.", ntop, strport);
+                       if (listen(listen_sock, 5) < 0)
+                               fatal("listen: %.100s", strerror(errno));
+
+               }
+               freeaddrinfo(options.listen_addrs);
+
+               if (!num_listen_socks)
+                       fatal("Cannot bind any address.");
+
+               if (options.protocol & SSH_PROTO_1)
+                       generate_ephemeral_server_key();
+
+               /*
+                * Arrange to restart on SIGHUP.  The handler needs
+                * listen_sock.
+                */
+               signal(SIGHUP, sighup_handler);
+
+               signal(SIGTERM, sigterm_handler);
+               signal(SIGQUIT, sigterm_handler);
+
+               /* Arrange SIGCHLD to be caught. */
+               signal(SIGCHLD, main_sigchld_handler);
+
+               /* Write out the pid file after the sigterm handler is setup */
+               if (!debug_flag) {
+                       /*
+                        * Record our pid in /var/run/sshd.pid to make it
+                        * easier to kill the correct sshd.  We don't want to
+                        * do this before the bind above because the bind will
+                        * fail if there already is a daemon, and this will
+                        * overwrite any old pid in the file.
+                        */
+                       f = fopen(options.pid_file, "wb");
+                       if (f) {
+                               fprintf(f, "%u\n", (u_int) getpid());
+                               fclose(f);
+                       }
+               }
+
+               /* setup fd set for listen */
+               fdset = NULL;
+               maxfd = 0;
+               for (i = 0; i < num_listen_socks; i++)
+                       if (listen_socks[i] > maxfd)
+                               maxfd = listen_socks[i];
+               /* pipes connected to unauthenticated childs */
+               startup_pipes = xmalloc(options.max_startups * sizeof(int));
+               for (i = 0; i < options.max_startups; i++)
+                       startup_pipes[i] = -1;
+
+               /*
+                * Stay listening for connections until the system crashes or
+                * the daemon is killed with a signal.
+                */
+               for (;;) {
+                       if (received_sighup)
+                               sighup_restart();
+                       if (fdset != NULL)
+                               xfree(fdset);
+                       fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
+                       fdset = (fd_set *)xmalloc(fdsetsz);
+                       memset(fdset, 0, fdsetsz);
+
+                       for (i = 0; i < num_listen_socks; i++)
+                               FD_SET(listen_socks[i], fdset);
+                       for (i = 0; i < options.max_startups; i++)
+                               if (startup_pipes[i] != -1)
+                                       FD_SET(startup_pipes[i], fdset);
+
+                       /* Wait in select until there is a connection. */
+                       ret = select(maxfd+1, fdset, NULL, NULL, NULL);
+                       if (ret < 0 && errno != EINTR)
+                               error("select: %.100s", strerror(errno));
+                       if (received_sigterm) {
+                               log("Received signal %d; terminating.",
+                                   received_sigterm);
+                               close_listen_socks();
+                               unlink(options.pid_file);
+                               exit(255);
+                       }
+                       if (key_used && key_do_regen) {
+                               generate_ephemeral_server_key();
+                               key_used = 0;
+                               key_do_regen = 0;
+                       }
+                       if (ret < 0)
+                               continue;
+
+                       for (i = 0; i < options.max_startups; i++)
+                               if (startup_pipes[i] != -1 &&
+                                   FD_ISSET(startup_pipes[i], fdset)) {
+                                       /*
+                                        * the read end of the pipe is ready
+                                        * if the child has closed the pipe
+                                        * after successful authentication
+                                        * or if the child has died
+                                        */
+                                       close(startup_pipes[i]);
+                                       startup_pipes[i] = -1;
+                                       startups--;
+                               }
+                       for (i = 0; i < num_listen_socks; i++) {
+                               if (!FD_ISSET(listen_socks[i], fdset))
+                                       continue;
+                               fromlen = sizeof(from);
+                               newsock = accept(listen_socks[i], (struct sockaddr *)&from,
+                                   &fromlen);
+                               if (newsock < 0) {
+                                       if (errno != EINTR && errno != EWOULDBLOCK)
+                                               error("accept: %.100s", strerror(errno));
+                                       continue;
+                               }
+                               if (fcntl(newsock, F_SETFL, 0) < 0) {
+                                       error("newsock del O_NONBLOCK: %s", strerror(errno));
+                                       continue;
+                               }
+                               if (drop_connection(startups) == 1) {
+                                       debug("drop connection #%d", startups);
+                                       close(newsock);
+                                       continue;
+                               }
+                               if (pipe(startup_p) == -1) {
+                                       close(newsock);
+                                       continue;
+                               }
+
+                               for (j = 0; j < options.max_startups; j++)
+                                       if (startup_pipes[j] == -1) {
+                                               startup_pipes[j] = startup_p[0];
+                                               if (maxfd < startup_p[0])
+                                                       maxfd = startup_p[0];
+                                               startups++;
+                                               break;
+                                       }
+
+                               /*
+                                * Got connection.  Fork a child to handle it, unless
+                                * we are in debugging mode.
+                                */
+                               if (debug_flag) {
+                                       /*
+                                        * In debugging mode.  Close the listening
+                                        * socket, and start processing the
+                                        * connection without forking.
+                                        */
+                                       debug("Server will not fork when running in debugging mode.");
+                                       close_listen_socks();
+                                       sock_in = newsock;
+                                       sock_out = newsock;
+                                       startup_pipe = -1;
+                                       pid = getpid();
+                                       break;
+                               } else {
+                                       /*
+                                        * Normal production daemon.  Fork, and have
+                                        * the child process the connection. The
+                                        * parent continues listening.
+                                        */
+                                       if ((pid = fork()) == 0) {
+                                               /*
+                                                * Child.  Close the listening and max_startup
+                                                * sockets.  Start using the accepted socket.
+                                                * Reinitialize logging (since our pid has
+                                                * changed).  We break out of the loop to handle
+                                                * the connection.
+                                                */
+                                               startup_pipe = startup_p[1];
+                                               for (j = 0; j < options.max_startups; j++)
+                                                       if (startup_pipes[j] != -1)
+                                                               close(startup_pipes[j]);
+                                               close_listen_socks();
+                                               sock_in = newsock;
+                                               sock_out = newsock;
+                                               log_init(__progname, options.log_level, options.log_facility, log_stderr);
+                                               break;
+                                       }
+                               }
+
+                               /* Parent.  Stay in the loop. */
+                               if (pid < 0)
+                                       error("fork: %.100s", strerror(errno));
+                               else
+                                       debug("Forked child %d.", pid);
+
+                               close(startup_p[1]);
+
+                               /* Mark that the key has been used (it was "given" to the child). */
+                               if ((options.protocol & SSH_PROTO_1) &&
+                                   key_used == 0) {
+                                       /* Schedule server key regeneration alarm. */
+                                       signal(SIGALRM, key_regeneration_alarm);
+                                       alarm(options.key_regeneration_time);
+                                       key_used = 1;
+                               }
+
+                               arc4random_stir();
+
+                               /* Close the new socket (the child is now taking care of it). */
+                               close(newsock);
+                       }
+                       /* child process check (or debug mode) */
+                       if (num_listen_socks < 0)
+                               break;
+               }
+       }
+
+       /* This is the child processing a new connection. */
+
+       /*
+        * Disable the key regeneration alarm.  We will not regenerate the
+        * key since we are no longer in a position to give it to anyone. We
+        * will not restart on SIGHUP since it no longer makes sense.
+        */
+       alarm(0);
+       signal(SIGALRM, SIG_DFL);
+       signal(SIGHUP, SIG_DFL);
+       signal(SIGTERM, SIG_DFL);
+       signal(SIGQUIT, SIG_DFL);
+       signal(SIGCHLD, SIG_DFL);
+       signal(SIGINT, SIG_DFL);
+
+       /*
+        * Set socket options for the connection.  We want the socket to
+        * close as fast as possible without waiting for anything.  If the
+        * connection is not a socket, these will do nothing.
+        */
+       /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
+       linger.l_onoff = 1;
+       linger.l_linger = 5;
+       setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
+
+       /* Set keepalives if requested. */
+       if (options.keepalives &&
+           setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
+           sizeof(on)) < 0)
+               error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
+
+       /*
+        * Register our connection.  This turns encryption off because we do
+        * not have a key.
+        */
+       packet_set_connection(sock_in, sock_out);
+
+       remote_port = get_remote_port();
+       remote_ip = get_remote_ipaddr();
+
+#ifdef LIBWRAP
+       /* Check whether logins are denied from this host. */
+       {
+               struct request_info req;
+
+               request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
+               fromhost(&req);
+
+               if (!hosts_access(&req)) {
+                       debug("Connection refused by tcp wrapper");
+                       refuse(&req);
+                       /* NOTREACHED */
+                       fatal("libwrap refuse returns");
+               }
+       }
+#endif /* LIBWRAP */
+
+       /* Log the connection. */
+       verbose("Connection from %.500s port %d", remote_ip, remote_port);
+
+       /*
+        * We don\'t want to listen forever unless the other side
+        * successfully authenticates itself.  So we set up an alarm which is
+        * cleared after successful authentication.  A limit of zero
+        * indicates no limit. Note that we don\'t set the alarm in debugging
+        * mode; it is just annoying to have the server exit just when you
+        * are about to discover the bug.
+        */
+       signal(SIGALRM, grace_alarm_handler);
+       if (!debug_flag)
+               alarm(options.login_grace_time);
+
+       sshd_exchange_identification(sock_in, sock_out);
+       /*
+        * Check that the connection comes from a privileged port.
+        * Rhosts-Authentication only makes sense from priviledged
+        * programs.  Of course, if the intruder has root access on his local
+        * machine, he can connect from any port.  So do not use these
+        * authentication methods from machines that you do not trust.
+        */
+       if (remote_port >= IPPORT_RESERVED ||
+           remote_port < IPPORT_RESERVED / 2) {
+               debug("Rhosts Authentication disabled, "
+                   "originating port %d not trusted.", remote_port);
+               options.rhosts_authentication = 0;
+       }
+#if defined(KRB4) && !defined(KRB5)
+       if (!packet_connection_is_ipv4() &&
+           options.kerberos_authentication) {
+               debug("Kerberos Authentication disabled, only available for IPv4.");
+               options.kerberos_authentication = 0;
+       }
+#endif /* KRB4 && !KRB5 */
+#ifdef AFS
+       /* If machine has AFS, set process authentication group. */
+       if (k_hasafs()) {
+               k_setpag();
+               k_unlog();
+       }
+#endif /* AFS */
+
+       packet_set_nonblocking();
+
+       /* perform the key exchange */
+       /* authenticate user and start session */
+       if (compat20) {
+               do_ssh2_kex();
+               do_authentication2();
+       } else {
+               do_ssh1_kex();
+               do_authentication();
+       }
+       /* The connection has been terminated. */
+       verbose("Closing connection to %.100s", remote_ip);
+
+#ifdef USE_PAM
+       finish_pam();
+#endif /* USE_PAM */
+
+       packet_close();
+       exit(0);
+}
+
+/*
+ * SSH1 key exchange
+ */
+static void
+do_ssh1_kex(void)
+{
+       int i, len;
+       int plen, slen;
+       int rsafail = 0;
+       BIGNUM *session_key_int;
+       u_char session_key[SSH_SESSION_KEY_LENGTH];
+       u_char cookie[8];
+       u_int cipher_type, auth_mask, protocol_flags;
+       u_int32_t rand = 0;
+
+       /*
+        * Generate check bytes that the client must send back in the user
+        * packet in order for it to be accepted; this is used to defy ip
+        * spoofing attacks.  Note that this only works against somebody
+        * doing IP spoofing from a remote machine; any machine on the local
+        * network can still see outgoing packets and catch the random
+        * cookie.  This only affects rhosts authentication, and this is one
+        * of the reasons why it is inherently insecure.
+        */
+       for (i = 0; i < 8; i++) {
+               if (i % 4 == 0)
+                       rand = arc4random();
+               cookie[i] = rand & 0xff;
+               rand >>= 8;
+       }
+
+       /*
+        * Send our public key.  We include in the packet 64 bits of random
+        * data that must be matched in the reply in order to prevent IP
+        * spoofing.
+        */
+       packet_start(SSH_SMSG_PUBLIC_KEY);
+       for (i = 0; i < 8; i++)
+               packet_put_char(cookie[i]);
+
+       /* Store our public server RSA key. */
+       packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n));
+       packet_put_bignum(sensitive_data.server_key->rsa->e);
+       packet_put_bignum(sensitive_data.server_key->rsa->n);
+
+       /* Store our public host RSA key. */
+       packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n));
+       packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e);
+       packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n);
+
+       /* Put protocol flags. */
+       packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
+
+       /* Declare which ciphers we support. */
+       packet_put_int(cipher_mask_ssh1(0));
+
+       /* Declare supported authentication types. */
+       auth_mask = 0;
+       if (options.rhosts_authentication)
+               auth_mask |= 1 << SSH_AUTH_RHOSTS;
+       if (options.rhosts_rsa_authentication)
+               auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
+       if (options.rsa_authentication)
+               auth_mask |= 1 << SSH_AUTH_RSA;
+#if defined(KRB4) || defined(KRB5)
+       if (options.kerberos_authentication)
+               auth_mask |= 1 << SSH_AUTH_KERBEROS;
+#endif
+#if defined(AFS) || defined(KRB5)
+       if (options.kerberos_tgt_passing)
+               auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
+#endif
+#ifdef AFS
+       if (options.afs_token_passing)
+               auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
+#endif
+       if (options.challenge_response_authentication == 1)
+               auth_mask |= 1 << SSH_AUTH_TIS;
+       if (options.password_authentication)
+               auth_mask |= 1 << SSH_AUTH_PASSWORD;
+       packet_put_int(auth_mask);
+
+       /* Send the packet and wait for it to be sent. */
+       packet_send();
+       packet_write_wait();
+
+       debug("Sent %d bit server key and %d bit host key.",
+           BN_num_bits(sensitive_data.server_key->rsa->n),
+           BN_num_bits(sensitive_data.ssh1_host_key->rsa->n));
+
+       /* Read clients reply (cipher type and session key). */
+       packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
+
+       /* Get cipher type and check whether we accept this. */
+       cipher_type = packet_get_char();
+
+       if (!(cipher_mask_ssh1(0) & (1 << cipher_type)))
+               packet_disconnect("Warning: client selects unsupported cipher.");
+
+       /* Get check bytes from the packet.  These must match those we
+          sent earlier with the public key packet. */
+       for (i = 0; i < 8; i++)
+               if (cookie[i] != packet_get_char())
+                       packet_disconnect("IP Spoofing check bytes do not match.");
+
+       debug("Encryption type: %.200s", cipher_name(cipher_type));
+
+       /* Get the encrypted integer. */
+       session_key_int = BN_new();
+       packet_get_bignum(session_key_int, &slen);
+
+       protocol_flags = packet_get_int();
+       packet_set_protocol_flags(protocol_flags);
+
+       packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
+
+       /*
+        * Decrypt it using our private server key and private host key (key
+        * with larger modulus first).
+        */
+       if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) {
+               /* Server key has bigger modulus. */
+               if (BN_num_bits(sensitive_data.server_key->rsa->n) <
+                   BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+                       fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
+                           get_remote_ipaddr(),
+                           BN_num_bits(sensitive_data.server_key->rsa->n),
+                           BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
+                           SSH_KEY_BITS_RESERVED);
+               }
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.server_key->rsa) <= 0)
+                       rsafail++;
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.ssh1_host_key->rsa) <= 0)
+                       rsafail++;
+       } else {
+               /* Host key has bigger modulus (or they are equal). */
+               if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) <
+                   BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+                       fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d",
+                           get_remote_ipaddr(),
+                           BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
+                           BN_num_bits(sensitive_data.server_key->rsa->n),
+                           SSH_KEY_BITS_RESERVED);
+               }
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.ssh1_host_key->rsa) < 0)
+                       rsafail++;
+               if (rsa_private_decrypt(session_key_int, session_key_int,
+                   sensitive_data.server_key->rsa) < 0)
+                       rsafail++;
+       }
+       /*
+        * Extract session key from the decrypted integer.  The key is in the
+        * least significant 256 bits of the integer; the first byte of the
+        * key is in the highest bits.
+        */
+       if (!rsafail) {
+               BN_mask_bits(session_key_int, sizeof(session_key) * 8);
+               len = BN_num_bytes(session_key_int);
+               if (len < 0 || len > sizeof(session_key)) {
+                       error("do_connection: bad session key len from %s: "
+                           "session_key_int %d > sizeof(session_key) %lu",
+                           get_remote_ipaddr(), len, (u_long)sizeof(session_key));
+                       rsafail++;
+               } else {
+                       memset(session_key, 0, sizeof(session_key));
+                       BN_bn2bin(session_key_int,
+                           session_key + sizeof(session_key) - len);
+
+                       compute_session_id(session_id, cookie,
+                           sensitive_data.ssh1_host_key->rsa->n,
+                           sensitive_data.server_key->rsa->n);
+                       /*
+                        * Xor the first 16 bytes of the session key with the
+                        * session id.
+                        */
+                       for (i = 0; i < 16; i++)
+                               session_key[i] ^= session_id[i];
+               }
+       }
+       if (rsafail) {
+               int bytes = BN_num_bytes(session_key_int);
+               char *buf = xmalloc(bytes);
+               MD5_CTX md;
+
+               log("do_connection: generating a fake encryption key");
+               BN_bn2bin(session_key_int, buf);
+               MD5_Init(&md);
+               MD5_Update(&md, buf, bytes);
+               MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
+               MD5_Final(session_key, &md);
+               MD5_Init(&md);
+               MD5_Update(&md, session_key, 16);
+               MD5_Update(&md, buf, bytes);
+               MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
+               MD5_Final(session_key + 16, &md);
+               memset(buf, 0, bytes);
+               xfree(buf);
+               for (i = 0; i < 16; i++)
+                       session_id[i] = session_key[i] ^ session_key[i + 16];
+       }
+       /* Destroy the private and public keys.  They will no longer be needed. */
+       destroy_sensitive_data();
+
+       /* Destroy the decrypted integer.  It is no longer needed. */
+       BN_clear_free(session_key_int);
+
+       /* Set the session key.  From this on all communications will be encrypted. */
+       packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
+
+       /* Destroy our copy of the session key.  It is no longer needed. */
+       memset(session_key, 0, sizeof(session_key));
+
+       debug("Received session key; encryption turned on.");
+
+       /* Send an acknowledgement packet.  Note that this packet is sent encrypted. */
+       packet_start(SSH_SMSG_SUCCESS);
+       packet_send();
+       packet_write_wait();
+}
+
+/*
+ * SSH2 key exchange: diffie-hellman-group1-sha1
+ */
+static void
+do_ssh2_kex(void)
+{
+       Kex *kex;
+
+       if (options.ciphers != NULL) {
+               myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+               myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+       }
+       myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+           compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
+       myproposal[PROPOSAL_ENC_ALGS_STOC] =
+           compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
+
+       if (options.macs != NULL) {
+               myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+               myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
+       }
+       myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
+
+       /* start key exchange */
+       kex = kex_setup(myproposal);
+       kex->server = 1;
+       kex->client_version_string=client_version_string;
+       kex->server_version_string=server_version_string;
+       kex->load_host_key=&get_hostkey_by_type;
+
+       xxx_kex = kex;
+
+       dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
+
+       session_id2 = kex->session_id;
+       session_id2_len = kex->session_id_len;
+
+#ifdef DEBUG_KEXDH
+       /* send 1st encrypted/maced/compressed message */
+       packet_start(SSH2_MSG_IGNORE);
+       packet_put_cstring("markus");
+       packet_send();
+       packet_write_wait();
+#endif
+       debug("KEX done");
+}
diff --git a/openssh/sshd_config b/openssh/sshd_config
new file mode 100644 (file)
index 0000000..e1a052a
--- /dev/null
@@ -0,0 +1,80 @@
+#      $OpenBSD: sshd_config,v 1.42 2001/09/20 20:57:51 mouring Exp $
+
+# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
+
+# This is the sshd server system-wide configuration file.  See sshd(8)
+# for more information.
+
+Port 22
+#Protocol 2,1
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# HostKey for protocol version 1
+HostKey /etc/ssh_host_key
+# HostKeys for protocol version 2
+HostKey /etc/ssh_host_rsa_key
+HostKey /etc/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+KeyRegenerationInterval 3600
+ServerKeyBits 768
+
+# Logging
+SyslogFacility AUTH
+LogLevel INFO
+#obsoletes QuietMode and FascistLogging
+
+# Authentication:
+
+LoginGraceTime 600
+PermitRootLogin yes
+StrictModes yes
+
+RSAAuthentication yes
+PubkeyAuthentication yes
+#AuthorizedKeysFile    %h/.ssh/authorized_keys
+
+# rhosts authentication should not be used
+RhostsAuthentication no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+IgnoreRhosts yes
+# For this to work you will also need host keys in /etc/ssh_known_hosts
+RhostsRSAAuthentication no
+# similar for protocol version 2
+HostbasedAuthentication no
+# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
+#IgnoreUserKnownHosts yes
+
+# To disable tunneled clear text passwords, change to no here!
+PasswordAuthentication yes
+PermitEmptyPasswords no
+
+# Uncomment to disable s/key passwords 
+#ChallengeResponseAuthentication no
+
+# Uncomment to enable PAM keyboard-interactive authentication 
+# Warning: enabling this may bypass the setting of 'PasswordAuthentication'
+#PAMAuthenticationViaKbdInt yes
+
+# To change Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#AFSTokenPassing no
+#KerberosTicketCleanup no
+
+# Kerberos TGT Passing does only work with the AFS kaserver
+#KerberosTgtPassing yes
+
+X11Forwarding no
+X11DisplayOffset 10
+PrintMotd yes
+#PrintLastLog no
+KeepAlive yes
+#UseLogin no
+
+#MaxStartups 10:30:60
+#Banner /etc/issue.net
+#ReverseMappingCheck yes
+
+Subsystem      sftp    /usr/libexec/sftp-server
diff --git a/openssh/sshlogin.c b/openssh/sshlogin.c
new file mode 100644 (file)
index 0000000..b7558b9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * This file performs some of the things login(1) normally does.  We cannot
+ * easily use something like login -p -h host -f user, because there are
+ * several different logins around, and it is hard to determined what kind of
+ * login the current system has.  Also, we want to be able to execute commands
+ * on a tty.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+ * Copyright (c) 1999 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $");
+
+#include "loginrec.h"
+
+/*
+ * Returns the time when the user last logged in.  Returns 0 if the
+ * information is not available.  This must be called before record_login.
+ * The host the user logged in from will be returned in buf.
+ */
+
+u_long
+get_last_login_time(uid_t uid, const char *logname,
+                   char *buf, u_int bufsize)
+{
+  struct logininfo li;
+
+  login_get_lastlog(&li, uid);
+  strlcpy(buf, li.hostname, bufsize);
+  return li.tv_sec;
+}
+
+/*
+ * Records that the user has logged in.  I these parts of operating systems
+ * were more standardized.
+ */
+
+void
+record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
+            const char *host, struct sockaddr * addr)
+{
+  struct logininfo *li;
+
+  li = login_alloc_entry(pid, user, host, ttyname);
+  login_set_addr(li, addr, sizeof(struct sockaddr));
+  login_login(li);
+  login_free_entry(li);
+}
+
+#ifdef LOGIN_NEEDS_UTMPX
+void
+record_utmp_only(pid_t pid, const char *ttyname, const char *user,
+                const char *host, struct sockaddr * addr)
+{
+  struct logininfo *li;
+
+  li = login_alloc_entry(pid, user, host, ttyname);
+  login_set_addr(li, addr, sizeof(struct sockaddr));
+  login_utmp_only(li);
+  login_free_entry(li);
+}
+#endif
+
+/* Records that the user has logged out. */
+
+void
+record_logout(pid_t pid, const char *ttyname)
+{
+  struct logininfo *li;
+
+  li = login_alloc_entry(pid, NULL, NULL, ttyname);
+  login_logout(li);
+  login_free_entry(li);
+}
diff --git a/openssh/sshlogin.h b/openssh/sshlogin.h
new file mode 100644 (file)
index 0000000..79d42a9
--- /dev/null
@@ -0,0 +1,23 @@
+/*     $OpenBSD: sshlogin.h,v 1.3 2001/06/26 17:27:25 markus Exp $     */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+#ifndef SSHLOGIN_H
+#define SSHLOGIN_H
+
+void
+record_login(pid_t, const char *, const char *, uid_t,
+    const char *, struct sockaddr *);
+void   record_logout(pid_t, const char *);
+u_long         get_last_login_time(uid_t, const char *, char *, u_int);
+
+#endif
diff --git a/openssh/sshpty.c b/openssh/sshpty.c
new file mode 100644 (file)
index 0000000..e1e6031
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Allocating a pseudo-terminal, and making it the controlling tty.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshpty.c,v 1.3 2001/07/22 21:32:27 markus Exp $");
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif /* HAVE_UTIL_H */
+
+#include "sshpty.h"
+#include "log.h"
+#include "misc.h"
+
+/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
+#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
+#undef HAVE_DEV_PTMX
+#endif
+
+#ifdef HAVE_PTY_H
+# include <pty.h>
+#endif
+#if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
+# include <sys/stropts.h>
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+/*
+ * Allocates and opens a pty.  Returns 0 if no pty could be allocated, or
+ * nonzero if a pty was successfully allocated.  On success, open file
+ * descriptors for the pty and tty sides and the name of the tty side are
+ * returned (the buffer must be able to hold at least 64 characters).
+ */
+
+int
+pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
+{
+#if defined(HAVE_OPENPTY) || defined(BSD4_4)
+       /* openpty(3) exists in OSF/1 and some other os'es */
+       char *name;
+       int i;
+
+       i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
+       if (i < 0) {
+               error("openpty: %.100s", strerror(errno));
+               return 0;
+       }
+       name = ttyname(*ttyfd);
+       if (!name)
+               fatal("openpty returns device for which ttyname fails.");
+
+       strlcpy(namebuf, name, namebuflen);     /* possible truncation */
+       return 1;
+#else /* HAVE_OPENPTY */
+#ifdef HAVE__GETPTY
+       /*
+        * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
+        * pty's automagically when needed
+        */
+       char *slave;
+
+       slave = _getpty(ptyfd, O_RDWR, 0622, 0);
+       if (slave == NULL) {
+               error("_getpty: %.100s", strerror(errno));
+               return 0;
+       }
+       strlcpy(namebuf, slave, namebuflen);
+       /* Open the slave side. */
+       *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
+       if (*ttyfd < 0) {
+               error("%.200s: %.100s", namebuf, strerror(errno));
+               close(*ptyfd);
+               return 0;
+       }
+       return 1;
+#else /* HAVE__GETPTY */
+#if defined(HAVE_DEV_PTMX)
+       /*
+        * This code is used e.g. on Solaris 2.x.  (Note that Solaris 2.3
+        * also has bsd-style ptys, but they simply do not work.)
+        */
+       int ptm;
+       char *pts;
+       mysig_t old_signal;
+
+       ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+       if (ptm < 0) {
+               error("/dev/ptmx: %.100s", strerror(errno));
+               return 0;
+       }
+       old_signal = mysignal(SIGCHLD, SIG_DFL);
+       if (grantpt(ptm) < 0) {
+               error("grantpt: %.100s", strerror(errno));
+               return 0;
+       }
+       mysignal(SIGCHLD, old_signal);
+       if (unlockpt(ptm) < 0) {
+               error("unlockpt: %.100s", strerror(errno));
+               return 0;
+       }
+       pts = ptsname(ptm);
+       if (pts == NULL)
+               error("Slave pty side name could not be obtained.");
+       strlcpy(namebuf, pts, namebuflen);
+       *ptyfd = ptm;
+
+       /* Open the slave side. */
+       *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
+       if (*ttyfd < 0) {
+               error("%.100s: %.100s", namebuf, strerror(errno));
+               close(*ptyfd);
+               return 0;
+       }
+#ifndef HAVE_CYGWIN
+       /*
+        * Push the appropriate streams modules, as described in Solaris pts(7).
+        * HP-UX pts(7) doesn't have ttcompat module.
+        */
+       if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
+               error("ioctl I_PUSH ptem: %.100s", strerror(errno));
+       if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
+               error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
+#ifndef __hpux
+       if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
+               error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
+#endif
+#endif
+       return 1;
+#else /* HAVE_DEV_PTMX */
+#ifdef HAVE_DEV_PTS_AND_PTC
+       /* AIX-style pty code. */
+       const char *name;
+
+       *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
+       if (*ptyfd < 0) {
+               error("Could not open /dev/ptc: %.100s", strerror(errno));
+               return 0;
+       }
+       name = ttyname(*ptyfd);
+       if (!name)
+               fatal("Open of /dev/ptc returns device for which ttyname fails.");
+       strlcpy(namebuf, name, namebuflen);
+       *ttyfd = open(name, O_RDWR | O_NOCTTY);
+       if (*ttyfd < 0) {
+               error("Could not open pty slave side %.100s: %.100s",
+                     name, strerror(errno));
+               close(*ptyfd);
+               return 0;
+       }
+       return 1;
+#else /* HAVE_DEV_PTS_AND_PTC */
+#ifdef _CRAY
+       char buf[64];
+       int i;
+       int highpty;
+
+#ifdef _SC_CRAY_NPTY
+       highpty = sysconf(_SC_CRAY_NPTY);
+       if (highpty == -1)
+               highpty = 128;
+#else
+       highpty = 128;
+#endif
+
+       for (i = 0; i < highpty; i++) {
+               snprintf(buf, sizeof(buf), "/dev/pty/%03d", i);
+               *ptyfd = open(buf, O_RDWR|O_NOCTTY);
+               if (*ptyfd < 0)
+                       continue;
+               snprintf(namebuf, namebuflen, "/dev/ttyp%03d", i);
+               /* Open the slave side. */
+               *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
+               if (*ttyfd < 0) {
+                       error("%.100s: %.100s", namebuf, strerror(errno));
+                       close(*ptyfd);
+                       return 0;
+               }
+               return 1;
+       }
+       return 0;
+#else
+       /* BSD-style pty code. */
+       char buf[64];
+       int i;
+       const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       const char *ptyminors = "0123456789abcdef";
+       int num_minors = strlen(ptyminors);
+       int num_ptys = strlen(ptymajors) * num_minors;
+
+       for (i = 0; i < num_ptys; i++) {
+               snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
+                        ptyminors[i % num_minors]);
+               snprintf(namebuf, namebuflen, "/dev/tty%c%c",
+                   ptymajors[i / num_minors], ptyminors[i % num_minors]);
+
+               *ptyfd = open(buf, O_RDWR | O_NOCTTY);
+               if (*ptyfd < 0) {
+                       /* Try SCO style naming */
+                       snprintf(buf, sizeof buf, "/dev/ptyp%d", i);
+                       snprintf(namebuf, namebuflen, "/dev/ttyp%d", i);
+                       *ptyfd = open(buf, O_RDWR | O_NOCTTY);
+                       if (*ptyfd < 0)
+                               continue;
+               }
+
+               /* Open the slave side. */
+               *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
+               if (*ttyfd < 0) {
+                       error("%.100s: %.100s", namebuf, strerror(errno));
+                       close(*ptyfd);
+                       return 0;
+               }
+               return 1;
+       }
+       return 0;
+#endif /* CRAY */
+#endif /* HAVE_DEV_PTS_AND_PTC */
+#endif /* HAVE_DEV_PTMX */
+#endif /* HAVE__GETPTY */
+#endif /* HAVE_OPENPTY */
+}
+
+/* Releases the tty.  Its ownership is returned to root, and permissions to 0666. */
+
+void
+pty_release(const char *ttyname)
+{
+       if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
+               error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
+       if (chmod(ttyname, (mode_t) 0666) < 0)
+               error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
+}
+
+/* Makes the tty the processes controlling tty and sets it to sane modes. */
+
+void
+pty_make_controlling_tty(int *ttyfd, const char *ttyname)
+{
+       int fd;
+#ifdef USE_VHANGUP
+       void *old;
+#endif /* USE_VHANGUP */
+
+#ifdef _CRAY
+       if (setsid() < 0)
+               error("setsid: %.100s", strerror(errno));
+
+       fd = open(ttyname, O_RDWR|O_NOCTTY);
+       if (fd != -1) {
+               mysignal(SIGHUP, SIG_IGN);
+               ioctl(fd, TCVHUP, (char *)NULL);
+               mysignal(SIGHUP, SIG_DFL);
+               setpgid(0, 0);
+               close(fd);
+       } else {
+               error("Failed to disconnect from controlling tty.");
+       }
+
+       debug("Setting controlling tty using TCSETCTTY.");
+       ioctl(*ttyfd, TCSETCTTY, NULL);
+       fd = open("/dev/tty", O_RDWR);
+       if (fd < 0)
+               error("%.100s: %.100s", ttyname, strerror(errno));
+       close(*ttyfd);
+               *ttyfd = fd;
+#else /* _CRAY */
+
+       /* First disconnect from the old controlling tty. */
+#ifdef TIOCNOTTY
+       fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
+       if (fd >= 0) {
+               (void) ioctl(fd, TIOCNOTTY, NULL);
+               close(fd);
+       }
+#endif /* TIOCNOTTY */
+       if (setsid() < 0)
+               error("setsid: %.100s", strerror(errno));
+
+       /*
+        * Verify that we are successfully disconnected from the controlling
+        * tty.
+        */
+       fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
+       if (fd >= 0) {
+               error("Failed to disconnect from controlling tty.");
+               close(fd);
+       }
+       /* Make it our controlling tty. */
+#ifdef TIOCSCTTY
+       debug("Setting controlling tty using TIOCSCTTY.");
+       if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
+               error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
+#endif /* TIOCSCTTY */
+#ifdef HAVE_NEWS4
+       if (setpgrp(0,0) < 0)
+               error("SETPGRP %s",strerror(errno));
+#endif /* HAVE_NEWS4 */
+#ifdef USE_VHANGUP
+       old = mysignal(SIGHUP, SIG_IGN);
+       vhangup();
+       mysignal(SIGHUP, old);
+#endif /* USE_VHANGUP */
+       fd = open(ttyname, O_RDWR);
+       if (fd < 0) {
+               error("%.100s: %.100s", ttyname, strerror(errno));
+       } else {
+#ifdef USE_VHANGUP
+               close(*ttyfd);
+               *ttyfd = fd;
+#else /* USE_VHANGUP */
+               close(fd);
+#endif /* USE_VHANGUP */
+       }
+       /* Verify that we now have a controlling tty. */
+       fd = open(_PATH_TTY, O_WRONLY);
+       if (fd < 0)
+               error("open /dev/tty failed - could not set controlling tty: %.100s",
+                     strerror(errno));
+       else {
+               close(fd);
+       }
+#endif /* _CRAY */
+}
+
+/* Changes the window size associated with the pty. */
+
+void
+pty_change_window_size(int ptyfd, int row, int col,
+                      int xpixel, int ypixel)
+{
+       struct winsize w;
+       w.ws_row = row;
+       w.ws_col = col;
+       w.ws_xpixel = xpixel;
+       w.ws_ypixel = ypixel;
+       (void) ioctl(ptyfd, TIOCSWINSZ, &w);
+}
+
+void
+pty_setowner(struct passwd *pw, const char *ttyname)
+{
+       struct group *grp;
+       gid_t gid;
+       mode_t mode;
+       struct stat st;
+
+       /* Determine the group to make the owner of the tty. */
+       grp = getgrnam("tty");
+       if (grp) {
+               gid = grp->gr_gid;
+               mode = S_IRUSR | S_IWUSR | S_IWGRP;
+       } else {
+               gid = pw->pw_gid;
+               mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
+       }
+
+       /*
+        * Change owner and mode of the tty as required.
+        * Warn but continue if filesystem is read-only and the uids match/
+        * tty is owned by root.
+        */
+       if (stat(ttyname, &st))
+               fatal("stat(%.100s) failed: %.100s", ttyname,
+                   strerror(errno));
+
+       if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
+               if (chown(ttyname, pw->pw_uid, gid) < 0) {
+                       if (errno == EROFS && 
+                          (st.st_uid == pw->pw_uid || st.st_uid == 0))
+                               error("chown(%.100s, %d, %d) failed: %.100s",
+                                     ttyname, pw->pw_uid, gid,
+                                     strerror(errno));
+                       else
+                               fatal("chown(%.100s, %d, %d) failed: %.100s",
+                                     ttyname, pw->pw_uid, gid,
+                                     strerror(errno));
+               }
+       }
+
+       if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
+               if (chmod(ttyname, mode) < 0) {
+                       if (errno == EROFS &&
+                           (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
+                               error("chmod(%.100s, 0%o) failed: %.100s",
+                                     ttyname, mode, strerror(errno));
+                       else
+                               fatal("chmod(%.100s, 0%o) failed: %.100s",
+                                     ttyname, mode, strerror(errno));
+               }
+       }
+}
diff --git a/openssh/sshpty.h b/openssh/sshpty.h
new file mode 100644 (file)
index 0000000..4eb479f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for allocating a pseudo-terminal and making it the controlling
+ * tty.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: sshpty.h,v 1.3 2001/06/26 17:27:25 markus Exp $"); */
+
+#ifndef SSHPTY_H
+#define SSHPTY_H
+
+int     pty_allocate(int *, int *, char *, int);
+void    pty_release(const char *);
+void    pty_make_controlling_tty(int *, const char *);
+void    pty_change_window_size(int, int, int, int, int);
+void    pty_setowner(struct passwd *, const char *);
+
+#endif                         /* SSHPTY_H */
diff --git a/openssh/sshtty.c b/openssh/sshtty.c
new file mode 100644 (file)
index 0000000..7849890
--- /dev/null
@@ -0,0 +1,96 @@
+/* $OpenBSD: sshtty.c,v 1.1 2001/04/14 16:33:20 stevesk Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#include "sshtty.h"
+#include "log.h"
+
+static struct termios _saved_tio;
+static int _in_raw_mode = 0;
+
+int
+in_raw_mode(void)
+{
+       return _in_raw_mode;    
+}
+
+struct termios
+get_saved_tio(void)
+{
+       return _saved_tio;
+}
+
+void
+leave_raw_mode(void)
+{
+       if (!_in_raw_mode)
+               return;
+       if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+               perror("tcsetattr");
+       else
+               _in_raw_mode = 0;
+
+       fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
+}
+
+void
+enter_raw_mode(void)
+{
+       struct termios tio;
+
+       if (tcgetattr(fileno(stdin), &tio) == -1) {
+               perror("tcgetattr");
+               return;
+       }
+       _saved_tio = tio;
+       tio.c_iflag |= IGNPAR;
+       tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+       tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+#ifdef IEXTEN
+       tio.c_lflag &= ~IEXTEN;
+#endif
+       tio.c_oflag &= ~OPOST;
+       tio.c_cc[VMIN] = 1;
+       tio.c_cc[VTIME] = 0;
+       if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
+               perror("tcsetattr");
+       else
+               _in_raw_mode = 1;
+
+       fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
+}
diff --git a/openssh/sshtty.h b/openssh/sshtty.h
new file mode 100644 (file)
index 0000000..7ba4a26
--- /dev/null
@@ -0,0 +1,48 @@
+/* $OpenBSD: sshtty.h,v 1.2 2001/06/26 17:27:25 markus Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SSHTTY_H
+#define SSHTTY_H
+
+#include <termios.h>
+
+int     in_raw_mode(void);
+struct termios get_saved_tio(void);
+void    leave_raw_mode(void);
+void    enter_raw_mode(void);
+
+#endif
diff --git a/openssh/tildexpand.c b/openssh/tildexpand.c
new file mode 100644 (file)
index 0000000..e89a7ad
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: tildexpand.c,v 1.12 2001/08/11 22:51:27 jakob Exp $");
+
+#include "xmalloc.h"
+#include "log.h"
+#include "tildexpand.h"
+
+/*
+ * Expands tildes in the file name.  Returns data allocated by xmalloc.
+ * Warning: this calls getpw*.
+ */
+char *
+tilde_expand_filename(const char *filename, uid_t my_uid)
+{
+       const char *cp;
+       u_int userlen;
+       char *expanded;
+       struct passwd *pw;
+       char user[100];
+       int len;
+
+       /* Return immediately if no tilde. */
+       if (filename[0] != '~')
+               return xstrdup(filename);
+
+       /* Skip the tilde. */
+       filename++;
+
+       /* Find where the username ends. */
+       cp = strchr(filename, '/');
+       if (cp)
+               userlen = cp - filename;        /* Something after username. */
+       else
+               userlen = strlen(filename);     /* Nothing after username. */
+       if (userlen == 0)
+               pw = getpwuid(my_uid);          /* Own home directory. */
+       else {
+               /* Tilde refers to someone elses home directory. */
+               if (userlen > sizeof(user) - 1)
+                       fatal("User name after tilde too long.");
+               memcpy(user, filename, userlen);
+               user[userlen] = 0;
+               pw = getpwnam(user);
+       }
+       if (!pw)
+               fatal("Unknown user %100s.", user);
+
+       /* If referring to someones home directory, return it now. */
+       if (!cp) {
+               /* Only home directory specified */
+               return xstrdup(pw->pw_dir);
+       }
+       /* Build a path combining the specified directory and path. */
+       len = strlen(pw->pw_dir) + strlen(cp + 1) + 2;
+       if (len > MAXPATHLEN)
+               fatal("Home directory too long (%d > %d", len-1, MAXPATHLEN-1);
+       expanded = xmalloc(len);
+       snprintf(expanded, len, "%s%s%s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", cp + 1);
+       return expanded;
+}
diff --git a/openssh/tildexpand.h b/openssh/tildexpand.h
new file mode 100644 (file)
index 0000000..f5e7e40
--- /dev/null
@@ -0,0 +1,15 @@
+/*     $OpenBSD: tildexpand.h,v 1.4 2001/06/26 17:27:25 markus Exp $   */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+char   *tilde_expand_filename(const char *, uid_t);
diff --git a/openssh/ttymodes.c b/openssh/ttymodes.c
new file mode 100644 (file)
index 0000000..c0bb0b1
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * SSH2 tty modes support by Kevin Steves.
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Encoding and decoding of terminal modes in a portable way.
+ * Much of the format is defined in ttymodes.h; it is included multiple times
+ * into this file with the appropriate macro definitions to generate the
+ * suitable code.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: ttymodes.c,v 1.14 2001/06/24 17:18:31 markus Exp $");
+
+#include "packet.h"
+#include "log.h"
+#include "ssh1.h"
+#include "compat.h"
+#include "buffer.h"
+#include "bufaux.h"
+
+#define TTY_OP_END             0
+/*
+ * uint32 (u_int) follows speed in SSH1 and SSH2
+ */
+#define TTY_OP_ISPEED_PROTO1   192
+#define TTY_OP_OSPEED_PROTO1   193
+#define TTY_OP_ISPEED_PROTO2   128
+#define TTY_OP_OSPEED_PROTO2   129
+
+/*
+ * Converts POSIX speed_t to a baud rate.  The values of the
+ * constants for speed_t are not themselves portable.
+ */
+static int
+speed_to_baud(speed_t speed)
+{
+       switch (speed) {
+       case B0:
+               return 0;
+       case B50:
+               return 50;
+       case B75:
+               return 75;
+       case B110:
+               return 110;
+       case B134:
+               return 134;
+       case B150:
+               return 150;
+       case B200:
+               return 200;
+       case B300:
+               return 300;
+       case B600:
+               return 600;
+       case B1200:
+               return 1200;
+       case B1800:
+               return 1800;
+       case B2400:
+               return 2400;
+       case B4800:
+               return 4800;
+       case B9600:
+               return 9600;
+
+#ifdef B19200
+       case B19200:
+               return 19200;
+#else /* B19200 */
+#ifdef EXTA
+       case EXTA:
+               return 19200;
+#endif /* EXTA */
+#endif /* B19200 */
+
+#ifdef B38400
+       case B38400:
+               return 38400;
+#else /* B38400 */
+#ifdef EXTB
+       case EXTB:
+               return 38400;
+#endif /* EXTB */
+#endif /* B38400 */
+
+#ifdef B7200
+       case B7200:
+               return 7200;
+#endif /* B7200 */
+#ifdef B14400
+       case B14400:
+               return 14400;
+#endif /* B14400 */
+#ifdef B28800
+       case B28800:
+               return 28800;
+#endif /* B28800 */
+#ifdef B57600
+       case B57600:
+               return 57600;
+#endif /* B57600 */
+#ifdef B76800
+       case B76800:
+               return 76800;
+#endif /* B76800 */
+#ifdef B115200
+       case B115200:
+               return 115200;
+#endif /* B115200 */
+#ifdef B230400
+       case B230400:
+               return 230400;
+#endif /* B230400 */
+       default:
+               return 9600;
+       }
+}
+
+/*
+ * Converts a numeric baud rate to a POSIX speed_t.
+ */
+static speed_t
+baud_to_speed(int baud)
+{
+       switch (baud) {
+       case 0:
+               return B0;
+       case 50:
+               return B50;
+       case 75:
+               return B75;
+       case 110:
+               return B110;
+       case 134:
+               return B134;
+       case 150:
+               return B150;
+       case 200:
+               return B200;
+       case 300:
+               return B300;
+       case 600:
+               return B600;
+       case 1200:
+               return B1200;
+       case 1800:
+               return B1800;
+       case 2400:
+               return B2400;
+       case 4800:
+               return B4800;
+       case 9600:
+               return B9600;
+
+#ifdef B19200
+       case 19200:
+               return B19200;
+#else /* B19200 */
+#ifdef EXTA
+       case 19200:
+               return EXTA;
+#endif /* EXTA */
+#endif /* B19200 */
+
+#ifdef B38400
+       case 38400:
+               return B38400;
+#else /* B38400 */
+#ifdef EXTB
+       case 38400:
+               return EXTB;
+#endif /* EXTB */
+#endif /* B38400 */
+
+#ifdef B7200
+       case 7200:
+               return B7200;
+#endif /* B7200 */
+#ifdef B14400
+       case 14400:
+               return B14400;
+#endif /* B14400 */
+#ifdef B28800
+       case 28800:
+               return B28800;
+#endif /* B28800 */
+#ifdef B57600
+       case 57600:
+               return B57600;
+#endif /* B57600 */
+#ifdef B76800
+       case 76800:
+               return B76800;
+#endif /* B76800 */
+#ifdef B115200
+       case 115200:
+               return B115200;
+#endif /* B115200 */
+#ifdef B230400
+       case 230400:
+               return B230400;
+#endif /* B230400 */
+       default:
+               return B9600;
+       }
+}
+
+/*
+ * Encodes terminal modes for the terminal referenced by fd
+ * or tiop in a portable manner, and appends the modes to a packet
+ * being constructed.
+ */
+void
+tty_make_modes(int fd, struct termios *tiop)
+{
+       struct termios tio;
+       int baud;
+       Buffer buf;
+       int tty_op_ospeed, tty_op_ispeed;
+       void (*put_arg)(Buffer *, u_int);
+
+       buffer_init(&buf);
+       if (compat20) {
+               tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
+               tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
+               put_arg = buffer_put_int;
+       } else {
+               tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
+               tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
+               put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
+       }
+
+       if (tiop == NULL) {
+               if (tcgetattr(fd, &tio) == -1) {
+                       log("tcgetattr: %.100s", strerror(errno));
+                       goto end;
+               }
+       } else
+               tio = *tiop;
+
+       /* Store input and output baud rates. */
+       baud = speed_to_baud(cfgetospeed(&tio));
+       debug3("tty_make_modes: ospeed %d", baud);
+       buffer_put_char(&buf, tty_op_ospeed);
+       buffer_put_int(&buf, baud);
+       baud = speed_to_baud(cfgetispeed(&tio));
+       debug3("tty_make_modes: ispeed %d", baud);
+       buffer_put_char(&buf, tty_op_ispeed);
+       buffer_put_int(&buf, baud);
+
+       /* Store values of mode flags. */
+#define TTYCHAR(NAME, OP) \
+       debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \
+       buffer_put_char(&buf, OP); \
+       put_arg(&buf, tio.c_cc[NAME]);
+
+#define TTYMODE(NAME, FIELD, OP) \
+       debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \
+       buffer_put_char(&buf, OP); \
+       put_arg(&buf, ((tio.FIELD & NAME) != 0));
+
+#include "ttymodes.h"
+
+#undef TTYCHAR
+#undef TTYMODE
+
+end:
+       /* Mark end of mode data. */
+       buffer_put_char(&buf, TTY_OP_END);
+       if (compat20)
+               packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
+       else
+               packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
+       buffer_free(&buf);
+       return;
+}
+
+/*
+ * Decodes terminal modes for the terminal referenced by fd in a portable
+ * manner from a packet being read.
+ */
+void
+tty_parse_modes(int fd, int *n_bytes_ptr)
+{
+       struct termios tio;
+       int opcode, baud;
+       int n_bytes = 0;
+       int failure = 0;
+       u_int (*get_arg)(void);
+       int arg, arg_size;
+
+       if (compat20) {
+               *n_bytes_ptr = packet_get_int();
+               debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr);
+               if (*n_bytes_ptr == 0)
+                       return;
+               get_arg = packet_get_int;
+               arg_size = 4;
+       } else {
+               get_arg = packet_get_char;
+               arg_size = 1;
+       }
+
+       /*
+        * Get old attributes for the terminal.  We will modify these
+        * flags. I am hoping that if there are any machine-specific
+        * modes, they will initially have reasonable values.
+        */
+       if (tcgetattr(fd, &tio) == -1) {
+               log("tcgetattr: %.100s", strerror(errno));
+               failure = -1;
+       }
+
+       for (;;) {
+               n_bytes += 1;
+               opcode = packet_get_char();
+               switch (opcode) {
+               case TTY_OP_END:
+                       goto set;
+
+               /* XXX: future conflict possible */
+               case TTY_OP_ISPEED_PROTO1:
+               case TTY_OP_ISPEED_PROTO2:
+                       n_bytes += 4;
+                       baud = packet_get_int();
+                       debug3("tty_parse_modes: ispeed %d", baud);
+                       if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1)
+                               error("cfsetispeed failed for %d", baud);
+                       break;
+
+               /* XXX: future conflict possible */
+               case TTY_OP_OSPEED_PROTO1:
+               case TTY_OP_OSPEED_PROTO2:
+                       n_bytes += 4;
+                       baud = packet_get_int();
+                       debug3("tty_parse_modes: ospeed %d", baud);
+                       if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1)
+                               error("cfsetospeed failed for %d", baud);
+                       break;
+
+#define TTYCHAR(NAME, OP) \
+       case OP: \
+         n_bytes += arg_size; \
+         tio.c_cc[NAME] = get_arg(); \
+         debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \
+         break;
+#define TTYMODE(NAME, FIELD, OP) \
+       case OP: \
+         n_bytes += arg_size; \
+         if ((arg = get_arg())) \
+           tio.FIELD |= NAME; \
+         else \
+           tio.FIELD &= ~NAME; \
+         debug3("tty_parse_modes: %d %d", OP, arg); \
+         break;
+
+#include "ttymodes.h"
+
+#undef TTYCHAR
+#undef TTYMODE
+
+               default:
+                       debug("Ignoring unsupported tty mode opcode %d (0x%x)",
+                             opcode, opcode);
+                       if (!compat20) {
+                               /*
+                                * SSH1:
+                                * Opcodes 1 to 127 are defined to have
+                                * a one-byte argument.
+                                * Opcodes 128 to 159 are defined to have
+                                * an integer argument.
+                                */
+                               if (opcode > 0 && opcode < 128) {
+                                       n_bytes += 1;
+                                       (void) packet_get_char();
+                                       break;
+                               } else if (opcode >= 128 && opcode < 160) {
+                                       n_bytes += 4;
+                                       (void) packet_get_int();
+                                       break;
+                               } else {
+                                       /*
+                                        * It is a truly undefined opcode (160 to 255).
+                                        * We have no idea about its arguments.  So we
+                                        * must stop parsing.  Note that some data may be
+                                        * left in the packet; hopefully there is nothing
+                                        * more coming after the mode data.
+                                        */
+                                       log("parse_tty_modes: unknown opcode %d", opcode);
+                                       packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
+                                       goto set;
+                               }
+                       } else {
+                               /*
+                                * SSH2:
+                                * Opcodes 1 to 159 are defined to have
+                                * a uint32 argument.
+                                * Opcodes 160 to 255 are undefined and
+                                * cause parsing to stop.
+                                */
+                               if (opcode > 0 && opcode < 160) {
+                                       n_bytes += 4;
+                                       (void) packet_get_int();
+                                       break;
+                               } else {
+                                       log("parse_tty_modes: unknown opcode %d", opcode);
+                                       goto set;
+                               }
+                       }
+               }
+       }
+
+set:
+       if (*n_bytes_ptr != n_bytes) {
+               *n_bytes_ptr = n_bytes;
+               log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
+                   *n_bytes_ptr, n_bytes);
+               return;         /* Don't process bytes passed */
+       }
+       if (failure == -1)
+               return;         /* Packet parsed ok but tcgetattr() failed */
+
+       /* Set the new modes for the terminal. */
+       if (tcsetattr(fd, TCSANOW, &tio) == -1)
+               log("Setting tty modes failed: %.100s", strerror(errno));
+       return;
+}
diff --git a/openssh/ttymodes.h b/openssh/ttymodes.h
new file mode 100644 (file)
index 0000000..ad980e9
--- /dev/null
@@ -0,0 +1,172 @@
+/* RCSID("$OpenBSD: ttymodes.h,v 1.11 2001/04/14 16:33:20 stevesk Exp $"); */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/*
+ * SSH2 tty modes support by Kevin Steves.
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * SSH1:
+ * The tty mode description is a stream of bytes.  The stream consists of
+ * opcode-arguments pairs.  It is terminated by opcode TTY_OP_END (0).
+ * Opcodes 1-127 have one-byte arguments.  Opcodes 128-159 have integer
+ * arguments.  Opcodes 160-255 are not yet defined, and cause parsing to
+ * stop (they should only be used after any other data).
+ *
+ * SSH2:
+ * Differences between SSH1 and SSH2 terminal mode encoding include:
+ * 1. Encoded terminal modes are represented as a string, and a stream
+ *    of bytes within that string.
+ * 2. Opcode arguments are uint32 (1-159); 160-255 remain undefined.
+ * 3. The values for TTY_OP_ISPEED and TTY_OP_OSPEED are different;
+ *    128 and 129 vs. 192 and 193 respectively.
+ *
+ * The client puts in the stream any modes it knows about, and the
+ * server ignores any modes it does not know about.  This allows some degree
+ * of machine-independence, at least between systems that use a posix-like
+ * tty interface.  The protocol can support other systems as well, but might
+ * require reimplementing as mode names would likely be different.
+ */
+
+/*
+ * Some constants and prototypes are defined in packet.h; this file
+ * is only intended for including from ttymodes.c.
+ */
+
+/* termios macro */
+/* name, op */
+TTYCHAR(VINTR, 1)
+TTYCHAR(VQUIT, 2)
+TTYCHAR(VERASE, 3)
+#if defined(VKILL)
+TTYCHAR(VKILL, 4)
+#endif /* VKILL */
+TTYCHAR(VEOF, 5)
+#if defined(VEOL)
+TTYCHAR(VEOL, 6)
+#endif /* VEOL */
+#ifdef VEOL2
+TTYCHAR(VEOL2, 7)
+#endif /* VEOL2 */
+TTYCHAR(VSTART, 8)
+TTYCHAR(VSTOP, 9)
+#if defined(VSUSP)
+TTYCHAR(VSUSP, 10)
+#endif /* VSUSP */
+#if defined(VDSUSP)
+TTYCHAR(VDSUSP, 11)
+#endif /* VDSUSP */
+#if defined(VREPRINT)
+TTYCHAR(VREPRINT, 12)
+#endif /* VREPRINT */
+#if defined(VWERASE)
+TTYCHAR(VWERASE, 13)
+#endif /* VWERASE */
+#if defined(VLNEXT)
+TTYCHAR(VLNEXT, 14)
+#endif /* VLNEXT */
+#if defined(VFLUSH)
+TTYCHAR(VFLUSH, 15)
+#endif /* VFLUSH */
+#ifdef VSWTCH
+TTYCHAR(VSWTCH, 16)
+#endif /* VSWTCH */
+#if defined(VSTATUS)
+TTYCHAR(VSTATUS, 17)
+#endif /* VSTATUS */
+#ifdef VDISCARD
+TTYCHAR(VDISCARD, 18)
+#endif /* VDISCARD */
+
+/* name, field, op */
+TTYMODE(IGNPAR,        c_iflag, 30)
+TTYMODE(PARMRK,        c_iflag, 31)
+TTYMODE(INPCK,         c_iflag, 32)
+TTYMODE(ISTRIP,        c_iflag, 33)
+TTYMODE(INLCR,         c_iflag, 34)
+TTYMODE(IGNCR,         c_iflag, 35)
+TTYMODE(ICRNL,         c_iflag, 36)
+#if defined(IUCLC)
+TTYMODE(IUCLC,         c_iflag, 37)
+#endif
+TTYMODE(IXON,          c_iflag, 38)
+TTYMODE(IXANY,         c_iflag, 39)
+TTYMODE(IXOFF,         c_iflag, 40)
+#ifdef IMAXBEL
+TTYMODE(IMAXBEL,c_iflag, 41)
+#endif /* IMAXBEL */
+
+TTYMODE(ISIG,  c_lflag, 50)
+TTYMODE(ICANON,        c_lflag, 51)
+#ifdef XCASE
+TTYMODE(XCASE, c_lflag, 52)
+#endif
+TTYMODE(ECHO,  c_lflag, 53)
+TTYMODE(ECHOE, c_lflag, 54)
+TTYMODE(ECHOK, c_lflag, 55)
+TTYMODE(ECHONL,        c_lflag, 56)
+TTYMODE(NOFLSH,        c_lflag, 57)
+TTYMODE(TOSTOP,        c_lflag, 58)
+#ifdef IEXTEN
+TTYMODE(IEXTEN, c_lflag, 59)
+#endif /* IEXTEN */
+#if defined(ECHOCTL)
+TTYMODE(ECHOCTL,c_lflag, 60)
+#endif /* ECHOCTL */
+#ifdef ECHOKE
+TTYMODE(ECHOKE,        c_lflag, 61)
+#endif /* ECHOKE */
+#if defined(PENDIN)
+TTYMODE(PENDIN,        c_lflag, 62)
+#endif /* PENDIN */
+
+TTYMODE(OPOST, c_oflag, 70)
+#if defined(OLCUC)
+TTYMODE(OLCUC, c_oflag, 71)
+#endif
+TTYMODE(ONLCR, c_oflag, 72)
+#ifdef OCRNL
+TTYMODE(OCRNL, c_oflag, 73)
+#endif
+#ifdef ONOCR
+TTYMODE(ONOCR, c_oflag, 74)
+#endif
+#ifdef ONLRET
+TTYMODE(ONLRET,        c_oflag, 75)
+#endif
+
+TTYMODE(CS7,   c_cflag, 90)
+TTYMODE(CS8,   c_cflag, 91)
+TTYMODE(PARENB,        c_cflag, 92)
+TTYMODE(PARODD,        c_cflag, 93)
diff --git a/openssh/uidswap.c b/openssh/uidswap.c
new file mode 100644 (file)
index 0000000..cc91fcf
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Code for uid-swapping.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: uidswap.c,v 1.18 2001/08/08 21:34:19 markus Exp $");
+
+#include "log.h"
+#include "uidswap.h"
+
+/*
+ * Note: all these functions must work in all of the following cases:
+ *    1. euid=0, ruid=0
+ *    2. euid=0, ruid!=0
+ *    3. euid!=0, ruid!=0
+ * Additionally, they must work regardless of whether the system has
+ * POSIX saved uids or not.
+ */
+
+#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS)
+/* Lets assume that posix saved ids also work with seteuid, even though that
+   is not part of the posix specification. */
+#define SAVED_IDS_WORK_WITH_SETEUID
+/* Saved effective uid. */
+static uid_t   saved_euid = 0;
+static gid_t   saved_egid = 0;
+#endif
+
+/* Saved effective uid. */
+static int     privileged = 0;
+static int     temporarily_use_uid_effective = 0;
+static gid_t   saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX];
+static int     saved_egroupslen = -1, user_groupslen = -1;
+
+/*
+ * Temporarily changes to the given uid.  If the effective user
+ * id is not root, this does nothing.  This call cannot be nested.
+ */
+void
+temporarily_use_uid(struct passwd *pw)
+{
+       /* Save the current euid, and egroups. */
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+       saved_euid = geteuid();
+       saved_egid = getegid();
+       debug("temporarily_use_uid: %d/%d (e=%d)",
+           pw->pw_uid, pw->pw_gid, saved_euid);
+       if (saved_euid != 0) {
+               privileged = 0;
+               return;
+       }
+#else
+       if (geteuid() != 0) {
+               privileged = 0;
+               return;
+       }
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+
+       privileged = 1;
+       temporarily_use_uid_effective = 1;
+       saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups);                           
+       if (saved_egroupslen < 0)
+               fatal("getgroups: %.100s", strerror(errno));
+
+       /* set and save the user's groups */
+       if (user_groupslen == -1) {
+               if (initgroups(pw->pw_name, pw->pw_gid) < 0)
+                       fatal("initgroups: %s: %.100s", pw->pw_name,
+                           strerror(errno));
+               user_groupslen = getgroups(NGROUPS_MAX, user_groups);                           
+               if (user_groupslen < 0)
+                       fatal("getgroups: %.100s", strerror(errno));
+       }
+#ifndef HAVE_CYGWIN
+       /* Set the effective uid to the given (unprivileged) uid. */
+       if (setgroups(user_groupslen, user_groups) < 0)
+               fatal("setgroups: %.100s", strerror(errno));
+#endif /* !HAVE_CYWIN */
+#ifndef SAVED_IDS_WORK_WITH_SETEUID
+       /* Propagate the privileged gid to all of our gids. */
+       if (setgid(getegid()) < 0)
+               debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno));
+       /* Propagate the privileged uid to all of our uids. */
+       if (setuid(geteuid()) < 0)
+               debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno));
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+       if (setegid(pw->pw_gid) < 0)
+               fatal("setegid %u: %.100s", (u_int) pw->pw_gid,
+                   strerror(errno));
+       if (seteuid(pw->pw_uid) == -1)
+               fatal("seteuid %u: %.100s", (u_int) pw->pw_uid,
+                   strerror(errno));
+}
+
+/*
+ * Restores to the original (privileged) uid.
+ */
+void
+restore_uid(void)
+{
+       debug("restore_uid");
+       /* it's a no-op unless privileged */
+       if (!privileged)
+               return;
+       if (!temporarily_use_uid_effective)
+               fatal("restore_uid: temporarily_use_uid not effective");
+
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+       /* Set the effective uid back to the saved privileged uid. */
+       if (seteuid(saved_euid) < 0)
+               fatal("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno));
+       if (setegid(saved_egid) < 0)
+               fatal("setegid %u: %.100s", (u_int) saved_egid, 
+                   strerror(errno));
+#else /* SAVED_IDS_WORK_WITH_SETEUID */
+       /*
+        * We are unable to restore the real uid to its unprivileged value.
+        * Propagate the real uid (usually more privileged) to effective uid
+        * as well.
+        */
+       setuid(getuid());
+       setgid(getgid());
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+
+#ifndef HAVE_CYGWIN
+       if (setgroups(saved_egroupslen, saved_egroups) < 0)
+               fatal("setgroups: %.100s", strerror(errno));
+#endif /* !HAVE_CYGWIN */
+       temporarily_use_uid_effective = 0;
+}
+
+/*
+ * Permanently sets all uids to the given uid.  This cannot be
+ * called while temporarily_use_uid is effective.
+ */
+void
+permanently_set_uid(struct passwd *pw)
+{
+       if (temporarily_use_uid_effective)
+               fatal("restore_uid: temporarily_use_uid effective");
+       if (setgid(pw->pw_gid) < 0)
+               fatal("setgid %u: %.100s", (u_int) pw->pw_gid, strerror(errno));
+       if (setuid(pw->pw_uid) < 0)
+               fatal("setuid %u: %.100s", (u_int) pw->pw_uid, strerror(errno));
+}
diff --git a/openssh/uidswap.h b/openssh/uidswap.h
new file mode 100644 (file)
index 0000000..0726980
--- /dev/null
@@ -0,0 +1,22 @@
+/*     $OpenBSD: uidswap.h,v 1.9 2001/06/26 17:27:25 markus Exp $      */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef UIDSWAP_H
+#define UIDSWAP_H
+
+void    temporarily_use_uid(struct passwd *);
+void    restore_uid(void);
+void    permanently_set_uid(struct passwd *);
+
+#endif                         /* UIDSWAP_H */
diff --git a/openssh/uuencode.c b/openssh/uuencode.c
new file mode 100644 (file)
index 0000000..f3774f1
--- /dev/null
@@ -0,0 +1,75 @@
+/*     $OpenBSD: uuencode.c,v 1.12 2001/03/01 02:27:18 deraadt Exp $   */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#include "xmalloc.h"
+#include "uuencode.h"
+
+RCSID("$OpenBSD: uuencode.c,v 1.12 2001/03/01 02:27:18 deraadt Exp $");
+
+int
+uuencode(u_char *src, u_int srclength,
+    char *target, size_t targsize)
+{
+       return __b64_ntop(src, srclength, target, targsize);
+}
+
+int
+uudecode(const char *src, u_char *target, size_t targsize)
+{
+       int len;
+       char *encoded, *p;
+
+       /* copy the 'readonly' source */
+       encoded = xstrdup(src);
+       /* skip whitespace and data */
+       for (p = encoded; *p == ' ' || *p == '\t'; p++)
+               ;
+       for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
+               ;
+       /* and remote trailing whitespace because __b64_pton needs this */
+       *p = '\0';
+       len = __b64_pton(encoded, target, targsize);
+       xfree(encoded);
+       return len;
+}
+
+void
+dump_base64(FILE *fp, u_char *data, int len)
+{
+       u_char *buf = xmalloc(2*len);
+       int i, n;
+
+       n = uuencode(data, len, buf, 2*len);
+       for (i = 0; i < n; i++) {
+               fprintf(fp, "%c", buf[i]);
+               if (i % 70 == 69)
+                       fprintf(fp, "\n");
+       }
+       if (i % 70 != 69)
+               fprintf(fp, "\n");
+       xfree(buf);
+}
diff --git a/openssh/uuencode.h b/openssh/uuencode.h
new file mode 100644 (file)
index 0000000..0067635
--- /dev/null
@@ -0,0 +1,32 @@
+/*     $OpenBSD: uuencode.h,v 1.8 2001/06/26 17:27:25 markus Exp $     */
+
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UUENCODE_H
+#define UUENCODE_H
+int     uuencode(u_char *, u_int, char *, size_t);
+int     uudecode(const char *, u_char *, size_t);
+void    dump_base64(FILE *, u_char *, int);
+#endif
diff --git a/openssh/version.h b/openssh/version.h
new file mode 100644 (file)
index 0000000..804e560
--- /dev/null
@@ -0,0 +1,3 @@
+/* $OpenBSD: version.h,v 1.25 2001/10/15 16:10:50 deraadt Exp $ */
+
+#define SSH_VERSION    "OpenSSH_3.0.2p1"
diff --git a/openssh/xmalloc.c b/openssh/xmalloc.c
new file mode 100644 (file)
index 0000000..99c6ac3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Versions of malloc and friends that check their results, and never return
+ * failure (they call fatal if they encounter an error).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp $");
+
+#include "xmalloc.h"
+#include "log.h"
+
+void *
+xmalloc(size_t size)
+{
+       void *ptr;
+
+       if (size == 0)
+               fatal("xmalloc: zero size");
+       ptr = malloc(size);
+       if (ptr == NULL)
+               fatal("xmalloc: out of memory (allocating %lu bytes)", (u_long) size);
+       return ptr;
+}
+
+void *
+xrealloc(void *ptr, size_t new_size)
+{
+       void *new_ptr;
+
+       if (new_size == 0)
+               fatal("xrealloc: zero size");
+       if (ptr == NULL)
+               new_ptr = malloc(new_size);
+       else
+               new_ptr = realloc(ptr, new_size);
+       if (new_ptr == NULL)
+               fatal("xrealloc: out of memory (new_size %lu bytes)", (u_long) new_size);
+       return new_ptr;
+}
+
+void
+xfree(void *ptr)
+{
+       if (ptr == NULL)
+               fatal("xfree: NULL pointer given as argument");
+       free(ptr);
+}
+
+char *
+xstrdup(const char *str)
+{
+       size_t len;
+       char *cp;
+
+       len = strlen(str) + 1;
+       cp = xmalloc(len);
+       strlcpy(cp, str, len);
+       return cp;
+}
diff --git a/openssh/xmalloc.h b/openssh/xmalloc.h
new file mode 100644 (file)
index 0000000..e14d014
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Created: Mon Mar 20 22:09:17 1995 ylo
+ *
+ * Versions of malloc and friends that check their results, and never return
+ * failure (they call fatal if they encounter an error).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: xmalloc.h,v 1.7 2001/06/26 17:27:25 markus Exp $"); */
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+void   *xmalloc(size_t);
+void   *xrealloc(void *, size_t);
+void     xfree(void *);
+char   *xstrdup(const char *);
+
+#endif                         /* XMALLOC_H */
This page took 3.050183 seconds and 5 git commands to generate.